home *** CD-ROM | disk | FTP | other *** search
/ The Fred Fish Collection 1.5 / ffcollection-1-5-1992-11.iso / ff_disks / 200-299 / ff274.lzh / Snap / snapchars.c < prev    next >
C/C++ Source or Header  |  1989-11-16  |  19KB  |  676 lines

  1. #include "snap.h"
  2.  
  3. #define COPY 0xC0L
  4. #define INVCOPY 0x30L
  5. #define CopyChar(_x, _y, _m)                                  \
  6.     BltBitMap(&MyBM, (LONG)_x, (LONG)_y,                      \
  7.       &TempBM, 0L, 0L, (LONG)FontWidth, (LONG)FontHeight,     \
  8.       _m, -1L, NULL);                                         \
  9.     WaitBlit()
  10.  
  11. WORD Unit;
  12. IMPORT WORD StartUnit;
  13.  
  14. LONG xl; /* leftmost x position */
  15. LONG xr; /* rightmost x position */
  16. LONG yt; /* topmost y position */
  17. LONG yb; /* bottommost y position */
  18. LONG minx; /* left limit */
  19. LONG maxx; /* right limit */
  20. LONG tl, tr; /* used by findword - left and right edge of word */
  21.  
  22. LONG mx, my; /* Mouse position in character steps */
  23. #define closetop     0
  24. #define closebottom  1
  25. WORD closey;
  26. #define closeleft   0
  27. #define closeright  1
  28. WORD closex;
  29.  
  30.  
  31. struct Window *window;  /* The window we're snapping from */
  32.  
  33. /* Data for font being snapped */
  34. UWORD FontHeight;
  35. UBYTE FontType;
  36. UWORD FontWidth;
  37. UBYTE LoChar;
  38. UBYTE HiChar;
  39. UWORD Modulo;
  40. UWORD *CharLoc;
  41. UWORD NoOfChars;
  42. UBYTE *SrcData;
  43. IMPORT UBYTE *CharData;
  44.  
  45. IMPORT struct RastPort TempRp, MyRP;
  46. IMPORT struct BitMap TempBM, MyBM;
  47. IMPORT WORD FrameMask;
  48.  
  49. IMPORT UWORD *TempRaster;   /* Used for character recognition */
  50.  
  51. IMPORT struct Screen *theScreen;
  52. IMPORT struct Layer_Info *LockedLayerInfo;
  53. IMPORT struct RastPort rp;
  54. IMPORT UWORD CrawlPtrn;
  55.  
  56. IMPORT LONGBITS cancelsignal, donesignal, movesignal, clicksignal, timersignal;
  57. IMPORT WORD action;
  58.  
  59. WORD starting;
  60.  
  61. /* Init vars with font data.
  62. */
  63.  
  64. VOID SetSnapFont(font)
  65. struct TextFont *font;
  66. {
  67.     if (!font) {
  68.         FontWidth = -1;
  69.         return;
  70.     }
  71.     FontHeight = font->tf_YSize;
  72.     FontType = font->tf_Flags;
  73.     FontWidth = (FontType & FPF_PROPORTIONAL ? -1 : font->tf_XSize);
  74.     if (FontWidth == -1) {
  75.         return;
  76.     }
  77.     LoChar = font->tf_LoChar;
  78.     HiChar = font->tf_HiChar;
  79.     Modulo = font->tf_Modulo;
  80.     CharLoc = (UWORD *)font->tf_CharLoc;
  81.     NoOfChars = HiChar-LoChar+1;
  82.     Modulo = font->tf_Modulo;
  83.     SrcData = (UBYTE *)font->tf_CharData;
  84.     BltClear(CharData, 224L*32, 0L);
  85.     WaitBlit();
  86.     CopyFont();
  87. }
  88.  
  89. /* Check if the character at x, y is a space
  90. */
  91.  
  92. WORD IsSpace(x, y)
  93. LONG x, y;
  94. {
  95.     REGISTER WORD i = FontHeight-1;
  96.     REGISTER UWORD *data = &TempRaster[i];
  97.  
  98.       /* Copy character at x, y */
  99.     BltClear(TempRaster, 32L, 0L);
  100.     ClipBlit(&rp, x, y,
  101.       &TempRp, 0L, 0L, (LONG)FontWidth, (LONG)FontHeight, COPY);
  102.     WaitBlit();
  103.  
  104.     if (*data) {         /* Try inverted copy */
  105.         ClipBlit(&rp, x, y,
  106.           &TempRp, 0L, 0L, (LONG)FontWidth, (LONG)FontHeight, INVCOPY);
  107.         WaitBlit();
  108.     }
  109.     while (i--) {
  110.         if (*data--) {
  111.             return 0;
  112.         }
  113.     }
  114.     return 1;
  115. }
  116.  
  117. #define ShortFrame 4L      /* Square frame - columnar select */
  118. #define LongFrame  8L      /* Strange frame - char or word select */
  119. IMPORT LONG OFType;        /* Old frame type: ShortFrame/LongFrame */
  120. IMPORT UWORD Ptrn;
  121. IMPORT Point OldFrame[];
  122. IMPORT Point NewFrame[];
  123.  
  124.  
  125. /* update_frame calculates the new frame,
  126. ** erases the old frame and draws the new one.
  127. ** It's all pretty obvious if you take it slowly.
  128. */
  129. VOID update_frame()
  130. {
  131.     LONG ft;
  132.     switch (Unit) {
  133.         case UNIT_FRAME: {
  134.               /*********\
  135.               *         *
  136.               *         *
  137.               \*********/
  138.             NewFrame[0].x = xl-1;         NewFrame[0].y = yt-1;
  139.             NewFrame[1].x = xr+FontWidth; NewFrame[1].y = yt-1;
  140.             NewFrame[2].x = xr+FontWidth; NewFrame[2].y = yb+FontHeight;
  141.             NewFrame[3].x = xl-1;         NewFrame[3].y = yb+FontHeight;
  142.             NewFrame[4].x = xl-1;         NewFrame[4].y = yt-1;
  143.             ft = ShortFrame;
  144.             break;
  145.         }
  146.         case UNIT_CHAR:
  147.         case UNIT_WORD: {
  148.             if (yt == yb) {   /* On the same line - same as UNIT_FRAME */
  149.                 NewFrame[0].x = xl-1;         NewFrame[0].y = yt-1;
  150.                 NewFrame[1].x = xr+FontWidth; NewFrame[1].y = yt-1;
  151.                 NewFrame[2].x = xr+FontWidth; NewFrame[2].y = yb+FontHeight;
  152.                 NewFrame[3].x = xl-1;         NewFrame[3].y = yb+FontHeight;
  153.                 NewFrame[4].x = xl-1;         NewFrame[4].y = yt-1;
  154.                 ft = ShortFrame;
  155.             } else {
  156.                       /*****\
  157.                  ******     *
  158.                  *          *
  159.                  *      *****
  160.                  *******/
  161.                 NewFrame[0].x = xl-1;           NewFrame[0].y = yt-1;
  162.                 NewFrame[1].x = maxx+FontWidth; NewFrame[1].y = yt-1;
  163.                 NewFrame[2].x = maxx+FontWidth; NewFrame[2].y = yb;
  164.                 NewFrame[3].x = xr+FontWidth;   NewFrame[3].y = yb;
  165.                 NewFrame[4].x = xr+FontWidth;   NewFrame[4].y = yb+FontHeight;
  166.                 NewFrame[5].x = minx-1;         NewFrame[5].y = yb+FontHeight;
  167.                 NewFrame[6].x = minx-1;         NewFrame[6].y = yt+FontHeight;
  168.                 NewFrame[7].x = xl-1;           NewFrame[7].y = yt+FontHeight;
  169.                 NewFrame[8].x = xl-1;           NewFrame[8].y = yt-1;
  170.                 ft = LongFrame;
  171.             }
  172.             break;
  173.         }
  174.         case UNIT_LINE: {
  175.             NewFrame[0].x = minx-1;         NewFrame[0].y = yt-1;
  176.             NewFrame[1].x = maxx+FontWidth; NewFrame[1].y = yt-1;
  177.             NewFrame[2].x = maxx+FontWidth; NewFrame[2].y = yb+FontHeight;
  178.             NewFrame[3].x = minx-1;         NewFrame[3].y = yb+FontHeight;
  179.             NewFrame[4].x = minx-1;         NewFrame[4].y = yt-1;
  180.             ft = ShortFrame;
  181.             break;
  182.         }
  183.         default: {
  184.             break;
  185.         }
  186.     }
  187.     draw_frame(ft);
  188. }
  189.  
  190. VOID FindWord()
  191. {
  192.       /* Must remove frame to be able to search for spaces */
  193.     WaitTOF();
  194.     erase_frame();
  195.     tl = mx;
  196.       /* Find a space to the left... */
  197.     while (!IsSpace(tl, my)) {
  198.         tl -= FontWidth;
  199.         if (tl < minx) {
  200.             break;
  201.         }
  202.     }
  203.     tl += FontWidth;
  204.     tr = mx;
  205.       /* ...and to the right */
  206.     while (!IsSpace(tr, my)) {
  207.         tr += FontWidth;
  208.         if (tr+FontWidth > maxx) {
  209.             break;
  210.         }
  211.     }
  212.     tr -= FontWidth;
  213.     if (tr < tl) {
  214.         tl = xl;
  215.         tr = xr;
  216.     }
  217. }
  218.  
  219. /* ChangeUnit cycles the unit of selection. The differents units
  220.    are: character, word and line.
  221. */
  222.  
  223. VOID ChangeUnit()
  224. {
  225.  
  226.     switch (Unit) {
  227.         case UNIT_FRAME: {
  228.             Unit = UNIT_CHAR;
  229.             break;
  230.         }
  231.         case UNIT_CHAR: {
  232.             Unit = UNIT_WORD;
  233.             FindWord();
  234.             xl = tl;
  235.             xr = tr;
  236.             break;
  237.         }
  238.         case UNIT_WORD: {
  239.             Unit = UNIT_LINE;
  240.             xl = minx;
  241.             xr = maxx;
  242.             break;
  243.         }
  244.         case UNIT_LINE: {
  245.             Unit = UNIT_FRAME;
  246.             xl = xr = mx;
  247.             break;
  248.         }
  249.     }
  250. }
  251.  
  252. /* ExtendSelection extends the current selection according to
  253.    the mouse position and the selected unit.
  254.    Note that ExtendSelection doesn't optimize moves that don't
  255.    make any difference. FIXME
  256. */
  257.  
  258. VOID ExtendSelection()
  259. {
  260.     /* Fix which row we're talking about */
  261.     if (closey == closetop) {       /* Find closest row */
  262.         yt = my;               /* change top row */
  263.     } else {
  264.         yb = my;               /* change bottom row */
  265.     }
  266.  
  267.     /* Take care of left and right character pos */
  268.     switch (Unit) {
  269.         case UNIT_FRAME: {
  270.             if (closex == closeleft) {
  271.                 xl = mx;
  272.             } else {
  273.                 xr = mx;
  274.             }
  275.             break;
  276.         }
  277.         case UNIT_CHAR: {
  278.             if (yt == yb) {            /* One line */
  279.                 if (closex == closeleft) {
  280.                     xl = mx;
  281.                 } else {
  282.                     xr = mx;
  283.                 }
  284.             } else {                   /* Multiple lines */
  285.                 if (yt == my) {
  286.                     xl = mx;           /* At top - set left */
  287.                 } else {
  288.                     xr = mx;           /* At bottom - set right */
  289.                 }
  290.             }
  291.             break;
  292.         }
  293.         case UNIT_WORD: {
  294.             FindWord(mx, my);          /* Find the word */
  295.             if (yt == yb) {            /* One line */
  296.                 if (closex == closeleft) {   /* Find closest char pos */
  297.                     xl = tl;
  298.                 } else {
  299.                     xr = tr;
  300.                 }
  301.             } else {                   /* Multiple lines */
  302.                 if (yt == my) {        /* Where am I */
  303.                     xl = tl;           /* At top - set left */
  304.                 } else {
  305.                     xr = tr;           /* At bottom - set right */
  306.                 }
  307.             }
  308.             break;
  309.         }
  310.         case UNIT_LINE: {              /* Always full width */
  311.             break;
  312.         }
  313.     }
  314.     if (yt-FontHeight == yb) {
  315.         yb += FontHeight;
  316.     }
  317.     if (yt == yb && xl-FontWidth == xr) {
  318.         xr += FontWidth;
  319.     }
  320.     if (xr > maxx) {         /* Check for window bounds */
  321.         xr = maxx;
  322.     }
  323.     if (xl < minx) {         /* Check for window bounds */
  324.         xl = minx;
  325.     }
  326. }
  327.  
  328. /* The actual character snapper. It actually works. */
  329.  
  330. WORD SnapChars()
  331. {
  332.     REGISTER struct RastPort MyRastPort;
  333.     LONG width;
  334.     LONG height;
  335.     UBYTE *SnapSpace;
  336.     ULONG SnapSize;
  337.     ULONG counter;
  338.     REGISTER LONG x, y;
  339.  
  340.       /* Check coordinates */
  341.     if (yt-FontHeight == yb) {        /* No rows, shouldn't happen */
  342.         return 0;
  343.     }
  344.     if (yt == yb && xl-FontWidth == xr) {     /* Nothing at all */
  345.         return 0;
  346.     }
  347.  
  348.       /* Calculate stuff */
  349.     width = maxx - (minx+1) + FontWidth+FontWidth;  /* Add one for a LF */
  350.     height = yb - yt + FontHeight;
  351.     SnapSize = ((width/FontWidth)+1) * (height/FontHeight);
  352.     counter = 0;
  353.  
  354.       /* Initialize things */
  355.     InitRastPort(&MyRP);
  356.     InitBitMap(&MyBM, 1L, width, height);
  357.     MyRP.BitMap = &MyBM;
  358.     SnapSpace = AllocMem(SnapSize, MEMF_PUBLIC|MEMF_CLEAR);
  359.       /* Please insert more memory */
  360.     if (!SnapSpace) {
  361.         return 0;
  362.     }
  363.     MyBM.Planes[0] = AllocRaster(width, height);
  364.     if (!MyBM.Planes[0]) {
  365.         FreeMem(SnapSpace, SnapSize);
  366.         return 0;
  367.     }
  368.       /* Make a local copy of the snapped chars */
  369.     ClipBlit(&rp, minx, yt, &MyRP, 0L, 0L, width, height, COPY);
  370.  
  371.       /* Ok, now we've got a copy of the character data */
  372.       /* Now it's ok to mess with the layers again */
  373.     UnlockLayers(LockedLayerInfo);
  374.  
  375.       /* Clear our work area */
  376.     BltClear(TempRaster, 32L, 0L);
  377.  
  378.       /* Calculate bounds */
  379.     xl -= minx;
  380.     xr -= minx;
  381.     maxx -= minx;
  382.     minx = 0;
  383.     yb -= yt;
  384.     yt = 0;
  385.  
  386.       /* Single line - needs to be handled separately */
  387.     if (yt == yb) { /* Ok, we've got one */
  388.  
  389.           /* Read from left to right */
  390.         for (x=xl; x<=xr; x+=FontWidth, counter++) {
  391.             CopyChar(x, yt, COPY);
  392.             if ((SnapSpace[counter] = interpret(TempRaster)) == 255) {
  393.                 SnapSpace[counter] = 63;  /* Unrecognized changed to ? */
  394.             }
  395.         }
  396.     } else { /* Multiple lines */
  397.  
  398.         if (Unit == UNIT_FRAME) {
  399.             minx = xl;
  400.             maxx = xr;
  401.         }
  402.  
  403.           /* Read first line */
  404.         for (x=xl; x<=maxx; x+=FontWidth, counter++) {
  405.             CopyChar(x, yt, COPY);
  406.             if ((SnapSpace[counter] = interpret(TempRaster)) == 255) {
  407.                 SnapSpace[counter] = 63;  /* Unrecognized changed to ? */
  408.             }
  409.         }
  410.         if (Unit == UNIT_FRAME) {
  411.             SnapSpace[counter++] = 10;
  412.         } else {
  413.               /* Remove trailing blanks */
  414.             while (counter && SnapSpace[counter-1] == ' ') {
  415.                 counter--;
  416.             }
  417.             SnapSpace[counter++] = 10;
  418.         }
  419.  
  420.           /* If more than two rows - read full middle rows */
  421.         if (yt+FontHeight != yb) {
  422.             for (y=yt+FontHeight; y<yb; y+=FontHeight) {
  423.                 for (x=minx; x<=maxx; x+=FontWidth, counter++) {
  424.                     CopyChar(x, y, COPY);
  425.                     if ((SnapSpace[counter] = interpret(TempRaster)) == 255) {
  426.                         SnapSpace[counter] = 63;  /* Unrecognized - ? */
  427.                     }
  428.                 }
  429.                 if (Unit == UNIT_FRAME) {
  430.                     SnapSpace[counter++] = 10;
  431.                 } else {
  432.                       /* Remove trailing blanks */
  433.                     while (counter && SnapSpace[counter-1] == ' ') {
  434.                         counter--;
  435.                     }
  436.                     SnapSpace[counter++] = 10;
  437.                 }
  438.             }
  439.         }
  440.  
  441.           /* Read last line */
  442.         for (x=minx; x<=xr; x+=FontWidth, counter++) {
  443.             CopyChar(x, yb, COPY);
  444.             if ((SnapSpace[counter] = interpret(TempRaster)) == 255) {
  445.                 SnapSpace[counter] = 63;  /* Unrecognized changed to ? */
  446.             }
  447.         }
  448.         /* Remove trailing blanks */
  449.         while (counter && SnapSpace[counter-1] == ' ') {
  450.             counter--;
  451.         }
  452.     }
  453.     FreeRaster(MyBM.Planes[0], width, height);
  454.     SaveClip(SnapSpace, counter);
  455.     FreeMem(SnapSpace, SnapSize);
  456.     return 1;
  457. }
  458.  
  459.  
  460. /* HandleChars is the part of the Snap state machine that handles
  461.    snapping of characters. The selection is done in different
  462.    units: char, word, line.
  463. */
  464.  
  465. WORD HandleChars()
  466. {
  467.     LONG xoff, yoff;
  468.     LONG ox, oy;
  469.  
  470.       /* Find out which screen we're working on */
  471.     theScreen = WhichScreen();
  472.  
  473.       /* Oops, no screen? */
  474.     if (!theScreen) {
  475.         action = noaction;
  476.         return 0;
  477.     }
  478.  
  479.       /* Ok, what window? */
  480.     window = WhichWindow(theScreen);
  481.  
  482.       /* Oh dear, no window. */
  483.     if (!window) {
  484.         action = noaction;
  485.         return 0;
  486.     }
  487.  
  488.       /* No messing with the layers while I think */
  489.     LockedLayerInfo = &window->WScreen->LayerInfo;
  490.     LockLayers(LockedLayerInfo);
  491.  
  492.       /* Don't want to wreck somebody's rastport */
  493.     CopyMem(window->RPort, &rp, (long)sizeof(struct RastPort));
  494.  
  495.       /* Or his picture */
  496.     SetDrMd(&rp, COMPLEMENT);
  497.     rp.Mask = FrameMask;
  498.     Ptrn = CrawlPtrn;
  499.     SetDrPt(&rp, Ptrn);
  500.  
  501.       /* Find out what we're trying to read */
  502.     SetSnapFont(rp.Font);
  503.     if (FontWidth == -1) {
  504.         UnlockLayers(LockedLayerInfo);
  505.         action = noaction;
  506.         return 0;
  507.     }
  508.  
  509.       /* Find a position */
  510.     xl = window->MouseX - 7;
  511.     yt = window->MouseY - 7;
  512.  
  513.     if (xl<0) {
  514.         xl = 0;
  515.     }
  516.     if (yt<0) {
  517.         yt = 0;
  518.     }
  519.  
  520.       /* Check your position */
  521.     if (xl>window->Width || yt>window->Height) {
  522.         UnlockLayers(LockedLayerInfo);
  523.         action = noaction;
  524.         return 0;
  525.     }
  526.  
  527.       /* Find out the offset for the clicked character, if any.
  528.       ** This is the part that makes it special. Simple, isn't it. Hah!
  529.       */
  530.     {
  531.         REGISTER SHORT found = 0;
  532.         BltClear(TempRaster, 32L, 0L);
  533.         xoff = 0;
  534.         while ((xoff<(16-FontWidth)) && !found) {
  535.             ClipBlit(&rp, xl+xoff, yt,
  536.               &TempRp, 0L, 0L, (LONG)FontWidth, 16L, COPY);
  537.             WaitBlit();
  538.             yoff = 0;
  539.             while ((yoff<(16-FontHeight)) && !found) {
  540.                 if (interpret(&TempRaster[yoff]) != 255) {
  541.                     found = 1;
  542.                 }
  543.                 ++yoff;
  544.             }
  545.             ++xoff;
  546.         }
  547.  
  548.           /* Did we find a character? */
  549.         if (!found) {
  550.               /* No, back off */
  551.             UnlockLayers(LockedLayerInfo);
  552.             action = noaction;
  553.             return 0;
  554.         }
  555.     }
  556.  
  557.       /* Ok, now we know where to look for chars.
  558.       ** xoff and yoff is character position within our 16x16 bitmap.
  559.       */
  560.     xl = xl + xoff-1;         /* Adjust x */
  561.     yt = yt + yoff-1;         /* Adjust y */
  562.       /* Find out offsets within the window */
  563.     xoff = xl % FontWidth;
  564.     yoff = yt % FontHeight;
  565.       /* Set bounds */
  566.     minx = xoff;
  567.     maxx = minx+((window->Width-minx-FontWidth
  568.       -(window->Flags & BORDERLESS ? 0 : 2)
  569.       -(window->Flags & WINDOWSIZING ? 12 : 0))/FontWidth)*FontWidth;
  570.       /* Check bounds */
  571.     if (xl>maxx) {
  572.         UnlockLayers(LockedLayerInfo);
  573.         action = noaction;
  574.         return 0;
  575.     }
  576.       /* Set box dimensions */
  577.     xr = xl;
  578.     yb = yt;
  579.     ox = xr;
  580.     oy = yt;
  581.  
  582.       /* Select unit while starting */
  583.     starting = 1;
  584.  
  585.       /* Starting unit is character or frame */
  586.     Unit = StartUnit;
  587.     OFType = 0L;
  588.     update_frame();
  589.  
  590.       /* Get the state machine running */
  591.     FOREVER {
  592.           /* Wait for something to happen */
  593.         REGISTER LONGBITS sig =
  594.           Wait(movesignal|cancelsignal|donesignal|clicksignal|timersignal);
  595.  
  596.         if ((sig & timersignal) && (CrawlPtrn != 0xffff)) {
  597.             crawl_frame(0L);
  598.         }
  599.  
  600.         mx = (LONG)window->MouseX;
  601.         if (mx<0) {
  602.             mx = 0;
  603.         }
  604.           /* Calculate which edge is closest */
  605.         if ((mx-xl) < (xr-mx)) {
  606.             closex = closeleft;
  607.         } else {
  608.             closex = closeright;
  609.         }
  610.           /* Only interested in real char pos */
  611.         mx = mx - ((mx-xoff) % FontWidth);
  612.  
  613.         my = (LONG)window->MouseY;
  614.         if (my<0) {
  615.             my = 0;
  616.         }
  617.           /* Calculate which row is closest */
  618.         if ((my-yt) < (yb-my)) {
  619.             closey = closetop;
  620.         } else {
  621.             closey = closebottom;
  622.         }
  623.         my = my - ((my-yoff) % FontHeight);
  624.  
  625.           /* Hey, it moves! It's alive!! */
  626.         if ((sig & movesignal) && (action == snaptext)) {
  627.             if (mx != ox || my != oy) {  /* Something's happened */
  628.                 ExtendSelection();
  629.                 update_frame();
  630.                 starting = 0;
  631.                 ox = mx;
  632.                 oy = my;
  633.                 sig &= ~clicksignal;
  634.             }
  635.         }
  636.  
  637.           /* Ok, forget it... */
  638.         if (sig & cancelsignal) {
  639.             erase_frame();
  640.             UnlockLayers(LockedLayerInfo);
  641.             return 0;
  642.         }
  643.  
  644.           /* Click */
  645.         if ((sig & clicksignal) && (action == snaptext)) {
  646.               /* Selecting unit */
  647.             if (starting) {
  648.                 if (mx == ox && my == oy) {
  649.                     ChangeUnit();
  650.                     if (Unit == UNIT_CHAR) {
  651.                         ChangeUnit();
  652.                     }
  653.                     update_frame();
  654.                 } else if (Unit == UNIT_FRAME) {
  655.                     ChangeUnit();
  656.                     update_frame();
  657.                 }
  658.             }
  659.             if (mx != ox || my != oy) { /* Click in a new place */
  660.                 ExtendSelection();
  661.                 update_frame();
  662.                 starting = 0;
  663.                 ox = mx;
  664.                 oy = my;
  665.             }
  666.         }
  667.  
  668.           /* Finished */
  669.         if (sig & donesignal) {
  670.             erase_frame();
  671.             return SnapChars();
  672.         }
  673.     }
  674. }
  675.  
  676.