home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 1 / FFMCD01.bin / bbs / libdisks / d700t799 / disk793.lha / Snap / src.lha / src / snapchars.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-12-16  |  24.5 KB  |  885 lines

  1. /* Auto: make
  2. */
  3.  
  4. IMPORT struct SnapRsrc *SnapRsrc;
  5.  
  6. #define COPY 0xC0L
  7. #define INVCOPY 0x30L
  8. #define CopyChar(_x, _y, _m)                                  \
  9.     BltBitMap(&MyBM, (LONG)_x, (LONG)_y,                      \
  10.       &TempBM, 0L, 0L, (LONG)FontWidth, (LONG)FontHeight,     \
  11.       _m, -1L, NULL);                                         \
  12.     WaitBlit()
  13.  
  14. WORD Unit;
  15. WORD Pattern[5] = {
  16.     0,
  17.     0x0c3f,     /* Frame ....oo....oooooo */
  18.     0x3333,     /* Char  ..oo..oo..oo..oo */
  19.     0x1f1f,     /* Word  ...ooooo...ooooo */
  20.     0xffff      /* Line  oooooooooooooooo */
  21. };
  22.  
  23. LONG xl; /* leftmost x position */
  24. LONG xr; /* rightmost x position */
  25. LONG yt; /* topmost y position */
  26. LONG yb; /* bottommost y position */
  27. LONG minx; /* left limit */
  28. LONG maxx; /* right limit */
  29. LONG maxy; /* bottom limit */
  30. LONG tl, tr; /* used by findword - left and right edge of word */
  31. WORD fw, fh; /* Font width and height used when drawing the frame */
  32. WORD GZZ;
  33. WORD SBM;
  34.  
  35. LONG mx, my; /* Mouse position in character steps */
  36. #define closetop     0
  37. #define closebottom  1
  38. WORD closey;
  39. #define closeleft   0
  40. #define closeright  1
  41. WORD closex;
  42.  
  43.  
  44. struct Window *window;  /* The window we're snapping from */
  45.  
  46. /* Data for font being snapped */
  47. UWORD FontHeight;
  48. UWORD FontWidth;
  49. UWORD Underscore;
  50. UBYTE FontType;
  51. UBYTE LoChar;
  52. UBYTE HiChar;
  53. UWORD Modulo;
  54. UWORD *CharLoc;
  55. UWORD *CharKern;
  56. UBYTE *SrcData;
  57. IMPORT UBYTE *CharData;
  58. UBYTE IFlags;
  59.  
  60. IMPORT struct RastPort TempRp, MyRP;
  61. IMPORT struct BitMap TempBM, MyBM;
  62.  
  63. IMPORT UWORD *TempRaster;   /* Used for character recognition */
  64.  
  65. IMPORT struct Screen *theScreen;
  66. IMPORT struct RastPort rp;
  67. struct Layer *LockedLayer;
  68.  
  69. IMPORT struct timerequest MyTR;
  70.  
  71. IMPORT LONGBITS cancelsignal, donesignal, movesignal;
  72. IMPORT LONGBITS clicksignal, ticksignal, timersignal;
  73. IMPORT WORD action;
  74.  
  75. WORD starting;
  76.  
  77. /* Init vars with font data.
  78. */
  79.  
  80. WORD SetSnapFont(font)
  81. struct TextFont *font;
  82. {
  83.     if (!font) {
  84.         return 0;
  85.     }
  86.     FontHeight = font->tf_YSize;
  87.     if (FontHeight > CHEIGHT) {
  88.         return 0;
  89.     }
  90.     Underscore = font->tf_Baseline + 1;
  91.     FontType = font->tf_Flags;
  92.     if (FontType & FPF_PROPORTIONAL) {
  93.         return 0;
  94.     }
  95.     FontWidth = font->tf_XSize;
  96.     LoChar = font->tf_LoChar;
  97.     HiChar = font->tf_HiChar;
  98.     Modulo = font->tf_Modulo;
  99.     CharLoc = (UWORD *)font->tf_CharLoc;
  100.     CharKern = (UWORD *)font->tf_CharKern;
  101.     Modulo = font->tf_Modulo;
  102.     SrcData = (UBYTE *)font->tf_CharData;
  103.     BltClear((char *)CharData, 256L * (CHEIGHT * 2), 0L);
  104.     WaitBlit();
  105.     CopyFont();
  106.     return 1;
  107. }
  108.  
  109. /* Check if the character at x, y is a space
  110. */
  111.  
  112. WORD IsSpace(x, y)
  113. LONG x, y;
  114. {
  115.     REGISTER WORD i = FontHeight - 1;
  116.     REGISTER UWORD *data = &TempRaster[i];
  117.  
  118.       /* Copy character at x, y */
  119.     BltClear((char *)TempRaster, CHEIGHT * 2L, 0L);
  120.     ClipBlit(&rp, x, y,
  121.       &TempRp, 0L, 0L, (LONG)FontWidth, (LONG)FontHeight, COPY);
  122.     WaitBlit();
  123.  
  124.     if (*data) {         /* Try inverted copy */
  125.         ClipBlit(&rp, x, y,
  126.           &TempRp, 0L, 0L, (LONG)FontWidth, (LONG)FontHeight, INVCOPY);
  127.         WaitBlit();
  128.     }
  129.     while (i--) {
  130.         if (*data--) {
  131.             return 0;
  132.         }
  133.     }
  134.     return 1;
  135. }
  136.  
  137. #define ShortFrame 4L      /* Square frame - columnar select */
  138. #define LongFrame  8L      /* Strange frame - char or word select */
  139. IMPORT LONG OFType;        /* Old frame type: ShortFrame/LongFrame */
  140. IMPORT UWORD Ptrn;
  141. IMPORT Point OldFrame[];
  142. IMPORT Point NewFrame[];
  143.  
  144.  
  145. /* update_frame calculates the new frame,
  146. ** erases the old frame and draws the new one.
  147. ** It's all pretty obvious if you take it slowly.
  148. */
  149. VOID update_frame()
  150. {
  151.     LONG ft;
  152.     REGISTER LONG l, b, r, t, ml, mr;
  153.     l = xl - 1;
  154.     r = xr + fw;
  155.     t = yt - 1;
  156.     b = yb + fh;
  157.     ml = minx - 1;
  158.     mr = maxx + fw;
  159.     if (l < 0)                  l = 0;
  160.     if (r > window->Width - 1)  r = window->Width - 1;
  161.     if (t < 0)                  t = 0;
  162.     if (b > window->Height - 1) b = window->Height - 1;
  163.     if (ml < 0)                 ml = 0;
  164.     if (mr > window->Width - 1) mr = window->Width - 1;
  165.  
  166.     switch (Unit) {
  167.         case UNIT_FRAME: {
  168.               /*********\
  169.               *         *
  170.               *         *
  171.               \*********/
  172.             NewFrame[0].x = l;  NewFrame[0].y = t;
  173.             NewFrame[1].x = r;  NewFrame[1].y = t;
  174.             NewFrame[2].x = r;  NewFrame[2].y = b;
  175.             NewFrame[3].x = l;  NewFrame[3].y = b;
  176.             NewFrame[4].x = l;  NewFrame[4].y = t;
  177.             ft = ShortFrame;
  178.             break;
  179.         }
  180.         case UNIT_CHAR:
  181.         case UNIT_WORD: {
  182.             if (yt == yb) {   /* On the same line - same as UNIT_FRAME */
  183.                 NewFrame[0].x = l;  NewFrame[0].y = t;
  184.                 NewFrame[1].x = r;  NewFrame[1].y = t;
  185.                 NewFrame[2].x = r;  NewFrame[2].y = b;
  186.                 NewFrame[3].x = l;  NewFrame[3].y = b;
  187.                 NewFrame[4].x = l;  NewFrame[4].y = t;
  188.                 ft = ShortFrame;
  189.             } else {
  190.                       /*****\
  191.                  ******     *
  192.                  *          *
  193.                  *      *****
  194.                  *******/
  195.                 NewFrame[0].x = l;   NewFrame[0].y = t;
  196.                 NewFrame[1].x = mr;  NewFrame[1].y = t;
  197.                 NewFrame[2].x = mr;  NewFrame[2].y = yb;
  198.                 NewFrame[3].x = r;   NewFrame[3].y = yb;
  199.                 NewFrame[4].x = r;   NewFrame[4].y = b;
  200.                 NewFrame[5].x = ml;  NewFrame[5].y = b;
  201.                 NewFrame[6].x = ml;  NewFrame[6].y = yt + fh;
  202.                 NewFrame[7].x = l;   NewFrame[7].y = yt + fh;
  203.                 NewFrame[8].x = l;   NewFrame[8].y = t;
  204.                 ft = LongFrame;
  205.             }
  206.             break;
  207.         }
  208.         case UNIT_LINE: {
  209.             NewFrame[0].x = ml;  NewFrame[0].y = t;
  210.             NewFrame[1].x = mr;  NewFrame[1].y = t;
  211.             NewFrame[2].x = mr;  NewFrame[2].y = b;
  212.             NewFrame[3].x = ml;  NewFrame[3].y = b;
  213.             NewFrame[4].x = ml;  NewFrame[4].y = t;
  214.             ft = ShortFrame;
  215.             break;
  216.         }
  217.         default: {
  218.             break;
  219.         }
  220.     }
  221.     draw_frame(ft);
  222. }
  223.  
  224. VOID FindWord()
  225. {
  226.       /* Must remove frame to be able to search for spaces */
  227.     WaitTOF();
  228.     erase_frame();
  229.     tl = mx;
  230.       /* Find a space to the left... */
  231.     while (!IsSpace(tl, my)) {
  232.         tl -= fw;
  233.         if (tl < minx) {
  234.             break;
  235.         }
  236.     }
  237.     tl += fw;
  238.     tr = mx;
  239.       /* ...and to the right */
  240.     while (!IsSpace(tr, my)) {
  241.         tr += fw;
  242.         if (tr + fw > maxx) {
  243.             break;
  244.         }
  245.     }
  246.     tr -= fw;
  247.     if (tr < tl) {
  248.         tl = xl;
  249.         tr = xr;
  250.     }
  251. }
  252.  
  253. /* ChangeUnit cycles the unit of selection. The differents units
  254.    are: character, word and line.
  255. */
  256.  
  257. VOID ChangeUnit()
  258. {
  259.  
  260.     switch (Unit) {
  261.         case UNIT_FRAME: {
  262.             Unit = UNIT_CHAR;
  263.             break;
  264.         }
  265.         case UNIT_CHAR: {
  266.             Unit = UNIT_WORD;
  267.             FindWord();
  268.             xl = tl;
  269.             xr = tr;
  270.             break;
  271.         }
  272.         case UNIT_WORD: {
  273.             Unit = UNIT_LINE;
  274.             xl = minx;
  275.             xr = maxx;
  276.             break;
  277.         }
  278.         case UNIT_LINE: {
  279.             Unit = UNIT_FRAME;
  280.             xl = xr = mx;
  281.             break;
  282.         }
  283.     }
  284.     if (SnapRsrc->CrawlPtrn == 0) {
  285.         Ptrn = Pattern[Unit];
  286.     }
  287. }
  288.  
  289. /* ExtendSelection extends the current selection according to
  290.    the mouse position and the selected unit.
  291.    Note that ExtendSelection doesn't optimize moves that don't
  292.    make any difference. FIXME
  293. */
  294.  
  295. VOID ExtendSelection()
  296. {
  297.     /* Fix which row we're talking about */
  298.     if (closey == closetop) {       /* Find closest row */
  299.         yt = my;               /* change top row */
  300.     } else {
  301.         yb = my;               /* change bottom row */
  302.     }
  303.  
  304.     /* Take care of left and right character pos */
  305.     switch (Unit) {
  306.         case UNIT_FRAME: {
  307.             if (closex == closeleft) {
  308.                 xl = mx;
  309.             } else {
  310.                 xr = mx;
  311.             }
  312.             break;
  313.         }
  314.         case UNIT_CHAR: {
  315.             if (yt == yb) {            /* One line */
  316.                 if (closex == closeleft) {
  317.                     xl = mx;
  318.                 } else {
  319.                     xr = mx;
  320.                 }
  321.             } else {                    /* Multiple lines */
  322.                 if (yt == my) {
  323.                     xl = mx;            /* At top - set left */
  324.                 } else {
  325.                     xr = mx;            /* At bottom - set right */
  326.                 }
  327.             }
  328.             break;
  329.         }
  330.         case UNIT_WORD: {
  331.             FindWord();                 /* Find the word */
  332.             if (yt == yb) {             /* One line */
  333.                 if (closex == closeleft) {   /* Find closest char pos */
  334.                     xl = tl;
  335.                 } else {
  336.                     xr = tr;
  337.                 }
  338.             } else {                   /* Multiple lines */
  339.                 if (yt == my) {        /* Where am I */
  340.                     xl = tl;           /* At top - set left */
  341.                 } else {
  342.                     xr = tr;           /* At bottom - set right */
  343.                 }
  344.             }
  345.             break;
  346.         }
  347.         case UNIT_LINE: {              /* Always full width */
  348.             break;
  349.         }
  350.     }
  351.     if (yt - fh == yb) {
  352.         yb += fh;
  353.     }
  354.     if (yt == yb && xl - fw == xr) {
  355.         xr += fw;
  356.     }
  357.     if (xr > maxx) {         /* Check for window bounds */
  358.         xr = maxx;
  359.     }
  360.     if (xl < minx) {         /* Check for window bounds */
  361.         xl = minx;
  362.     }
  363.     if (yb > maxy) {         /* Check for window bounds */
  364.         yb = maxy;
  365.     }
  366.     if (xl > maxx) {
  367.         xl = maxx;
  368.     }   
  369.     if (xr < minx) {
  370.         xr = minx;
  371.     }   
  372. }
  373.  
  374. /* The actual character snapper. It actually works. :-) */
  375.  
  376. WORD SnapChars()
  377. {
  378.     LONG width;
  379.     LONG height;
  380.     UBYTE *SnapSpace;
  381.     ULONG SnapSize;
  382.     ULONG counter;
  383.     REGISTER LONG x, y;
  384.  
  385.       /* Check coordinates */
  386.     if (yt - fh == yb) {        /* No rows, shouldn't happen */
  387.         return 0;
  388.     }
  389.     if (yt == yb && xl - fw == xr) {     /* Nothing at all */
  390.         return 0;
  391.     }
  392.  
  393.       /* Calculate stuff */
  394.     width = maxx - (minx + 1) + fw + fw;  /* Add one for a LF */
  395.     height = yb - yt + fh;
  396.     SnapSize = ((width / fw) + 1) * (height / fh);
  397.     counter = 0;
  398.  
  399.       /* Initialize things */
  400.     InitRastPort(&MyRP);
  401.     InitBitMap(&MyBM, 2L, width, height);    /* 1L */
  402.     MyRP.BitMap = &MyBM;
  403.     SnapSpace = AllocMem(SnapSize, MEMF_PUBLIC|MEMF_CLEAR);
  404.       /* Please insert more memory */
  405.     if (!SnapSpace) {
  406.         return 0;
  407.     }
  408.     MyBM.Planes[0] = AllocRaster(width, height);
  409.     if (!MyBM.Planes[0]) {
  410.         FreeMem(SnapSpace, SnapSize);
  411.         return 0;
  412.     }
  413.     MyBM.Planes[1] = AllocRaster(width, height);
  414.     if (!MyBM.Planes[1]) {
  415.         FreeMem(SnapSpace, SnapSize);
  416.         FreeRaster(MyBM.Planes[0], width, height);
  417.         return 0;
  418.     }
  419.     IFlags = 0;
  420.     
  421.       /* Make a local copy of the snapped chars */
  422.     ClipBlit(&rp, minx, yt, &MyRP, 0L, 0L, width, height, COPY);
  423.  
  424.       /* JEW: My additions. To fix the 2.0x hightlighted character
  425.               it merges plane 1 with plane 0. */
  426.     MergePlanes(&MyBM);
  427.  
  428.  
  429.       /* Ok, now we've got a copy of the character data */
  430.       /* Now it's ok to mess with the layers again */
  431.     UnlockLayer(LockedLayer);
  432.  
  433.       /* Clear our work area */
  434.     BltClear((char *)TempRaster, CHEIGHT * 2, 0L);
  435.  
  436.       /* Calculate bounds */
  437.     xl -= minx;
  438.     xr -= minx;
  439.     maxx -= minx;
  440.     minx = 0;
  441.     yb -= yt;
  442.     yt = 0;
  443.  
  444.       /* Single line - needs to be handled separately */
  445.     if (yt == yb) { /* Ok, we've got one */
  446.  
  447.           /* Read from left to right */
  448.         for (x = xl; x <= xr; x += fw, counter++) {
  449.             CopyChar(x, yt, COPY);
  450.             if (!(SnapSpace[counter] = interpret(TempRaster))) {
  451.                 SnapSpace[counter] = SnapRsrc->BadChar;  /* Unrecognized */
  452.             }
  453.         }
  454.         if (Unit == UNIT_LINE) {
  455.             while (counter && SnapSpace[counter-1] == ' ') {
  456.                 counter--;
  457.             }
  458.         }
  459.     } else { /* Multiple lines */
  460.  
  461.         if (Unit == UNIT_FRAME) {
  462.             minx = xl;
  463.             maxx = xr;
  464.         }
  465.  
  466.           /* Read first line */
  467.         for (x = xl; x <= maxx; x += fw, counter++) {
  468.             CopyChar(x, yt, COPY);
  469.             if (!(SnapSpace[counter] = interpret(TempRaster))) {
  470.                 SnapSpace[counter] = SnapRsrc->BadChar;  /* Unrecognized */
  471.             }
  472.         }
  473.         if (Unit == UNIT_FRAME) {
  474.             SnapSpace[counter++] = 10;
  475.         } else {
  476.             SHORT endspace = (SnapSpace[counter-1] == ' ');
  477.               /* Remove trailing blanks */
  478.             while (counter && SnapSpace[counter-1] == ' ') {
  479.                 counter--;
  480.             }
  481.             if (endspace || !(SnapRsrc->flags & JOINLONG)) {
  482.                 SnapSpace[counter++] = 10;
  483.             }
  484.         }
  485.  
  486.           /* If more than two rows - read full middle rows */
  487.         if (yt + fh != yb) {
  488.             for (y = yt + fh; y < yb; y += fh) {
  489.                 for (x = minx; x <= maxx; x += fw, counter++) {
  490.                     CopyChar(x, y, COPY);
  491.                     if (!(SnapSpace[counter] = interpret(TempRaster))) {
  492.                         SnapSpace[counter] = SnapRsrc->BadChar;  /* Unrecognized */
  493.                     }
  494.                 }
  495.                 if (Unit == UNIT_FRAME) {
  496.                     SnapSpace[counter++] = 10;
  497.                 } else {
  498.                     SHORT endspace = (SnapSpace[counter-1] == ' ');
  499.                       /* Remove trailing blanks */
  500.                     while (counter && SnapSpace[counter-1] == ' ') {
  501.                         counter--;
  502.                     }
  503.                     if (endspace || !(SnapRsrc->flags & JOINLONG)) {
  504.                         SnapSpace[counter++] = 10;
  505.                     }
  506.                 }
  507.             }
  508.         }
  509.  
  510.           /* Read last line */
  511.         for (x = minx; x <= xr; x += fw, counter++) {
  512.             CopyChar(x, yb, COPY);
  513.             if (!(SnapSpace[counter] = interpret(TempRaster))) {
  514.                 SnapSpace[counter] = SnapRsrc->BadChar;  /* Unrecognized */
  515.             }
  516.         }
  517.         /* Remove trailing blanks */
  518.         while (counter && SnapSpace[counter-1] == ' ') {
  519.             counter--;
  520.         }
  521.     }
  522.     FreeRaster(MyBM.Planes[0], width, height);
  523.     FreeRaster(MyBM.Planes[1], width, height);
  524.     SaveClip(SnapSpace, counter);
  525.     FreeMem(SnapSpace, SnapSize);
  526.     return 1;
  527. }
  528.  
  529.  
  530. /* HandleChars is the part of the Snap state machine that handles
  531.    snapping of characters. The selection is done in different
  532.    units: char, word, line.
  533. */
  534.  
  535. WORD HandleChars()
  536. {
  537.     LONG xoff, yoff;
  538.     LONG ox, oy;
  539.     LONG gzzx, gzzy, normalx, normaly;
  540.  
  541.       /* Find out which screen we're working on */
  542.     theScreen = WhichScreen();
  543.  
  544.       /* Oops, no screen? */
  545.     if (!theScreen) {
  546.         action = noaction;
  547.         return 0;
  548.     }
  549.  
  550.       /* Ok, what window? */
  551.     window = WhichWindow(theScreen);
  552.  
  553.       /* Oh dear, no window. */
  554.     if (!window) {
  555.         action = noaction;
  556.         return 0;
  557.     }
  558.  
  559.       /* Try to get these as early as possible */
  560.     gzzx = window->GZZMouseX;
  561.     gzzy = window->GZZMouseY;
  562.     normalx = window->MouseX;
  563.     normaly = window->MouseY;
  564.  
  565.       /* No messing with the layers while I think */
  566.     LockedLayer = window->WLayer;
  567.     LockLayer(0L, LockedLayer);
  568.  
  569.       /* Don't want to wreck somebody's rastport */
  570.     CopyMem((char *)window->RPort, (char *)&rp, (LONG)sizeof(struct RastPort));
  571.  
  572.       /* Or his picture */
  573.     SetDrMd(&rp, COMPLEMENT);
  574.     rp.Mask = SnapRsrc->FrameMask;
  575.  
  576.     if (window->Flags & GIMMEZEROZERO) {
  577.         GZZ = 1;
  578.     } else {
  579.         GZZ = 0;
  580.     }
  581.     if (window->Flags & SUPER_BITMAP) {
  582.         SBM = 1;
  583.     } else {
  584.         SBM = 0;
  585.     }
  586.  
  587.       /* Find a position */
  588.     xl = (GZZ ? gzzx : normalx) + window->RPort->Layer->Scroll_X;
  589.     yt = (GZZ ? gzzy : normaly) + window->RPort->Layer->Scroll_Y;
  590.  
  591.     if (xl < 0) {
  592.         xl = 0;
  593.     }
  594.     if (yt < 0) {
  595.         yt = 0;
  596.     }
  597.  
  598.       /* Check your position */
  599.     if (xl > (GZZ ? window->GZZWidth : window->Width) ||
  600.       yt > (GZZ ? window->GZZHeight : window->Height)) {
  601.         UnlockLayer(LockedLayer);
  602.         action = noaction;
  603.         return 0;
  604.     }
  605.     IFlags = 0;
  606.  
  607.       /* Find out the offset for the clicked character, if any.
  608.       ** This is the part that makes it special. Simple, isn't it. Hah!
  609.       */
  610.     {
  611.         REGISTER struct CacheWindow *cw = GetCachedWindow(theScreen, window);
  612.         struct TextFont *font[3];
  613.         WORD fonts = 0;
  614.  
  615.           /* Collect fonts to try */
  616.         if (SnapRsrc->AlternateFont) {      /* The alternate font */
  617.             font[fonts++] = SnapRsrc->AlternateFont;
  618.         }
  619.         font[fonts++] = rp.Font;            /* Second best, the RP's font */
  620.         if (cw) {                           /* Best bet, the cached font */
  621.             font[fonts++] = cw->font;
  622.         }
  623.         while (fonts--) {
  624.             SHORT xadj;
  625.             SHORT yadj;
  626.             SHORT seekw;
  627.             SHORT seekh;
  628.               /* Find out what we're trying to read */
  629.             if (!SetSnapFont(font[fonts])) {
  630.                 continue;               /* Nope, try next font */
  631.             }
  632.  
  633.             BltClear((char *)TempRaster, CHEIGHT * 2, 0L);
  634.             if (cw) {
  635.                 xoff = - ((xl - cw->xoff) % cw->fw);
  636.                 yoff = - ((yt - cw->yoff) % cw->fh);
  637.                 ClipBlit(&rp, xl + xoff, yt + yoff,
  638.                   &TempRp, 0L, 0L, (LONG)FontWidth, (LONG)FontHeight, COPY);
  639.                 WaitBlit();
  640.                 if (interpret(TempRaster)) {
  641.                     goto found;
  642.                 }
  643.             }
  644.               /* No cache or cache didn't match */
  645.             xadj = (FontWidth < 8 ? FontWidth : 8);
  646.             yadj = (FontHeight < 12 ? FontHeight : 12);
  647.             seekw = (xadj << 1) - FontWidth;
  648.             seekh = (yadj << 1) - FontHeight;
  649.             xl -= xadj;
  650.             yt -= yadj;
  651.             xoff = 0;
  652.             while (xoff < seekw) {
  653.                 ClipBlit(&rp, xl + xoff, yt,
  654.                   &TempRp, 0L, 0L, (LONG)FontWidth, CHEIGHT, COPY);
  655.                 WaitBlit();
  656.                 yoff = 0;
  657.                 while (yoff < seekh) {
  658.                     if (interpret(&TempRaster[yoff])) {
  659.                         goto found;
  660.                     }
  661.                     ++yoff;
  662.                 }
  663.                 ++xoff;
  664.             }
  665.  
  666.               /* No character found. Try next font. */
  667.             xl += xadj; /* Adjust to original values */
  668.             yt += yadj;
  669.         }
  670.         UnlockLayer(LockedLayer);
  671.         action = noaction;
  672.         return 0;
  673.  
  674. found:
  675.           /* Ok, now we know where to look for chars.
  676.           ** xoff and yoff is character position within our 16xCHEIGHT bitmap.
  677.           */
  678.         xl = xl + xoff;         /* Adjust x */
  679.         yt = yt + yoff;         /* Adjust y */
  680.  
  681.         fw = FontWidth;
  682.         fh = FontHeight;
  683.  
  684.         {
  685.             SHORT temp = fh;
  686.             while (temp <= fh + SnapRsrc->Leading) {  /* Check for extra pixel row */
  687.                 BltClear((char *)TempRaster, CHEIGHT * 2, 0L);
  688.                 ClipBlit(&rp, xl, yt + temp,
  689.                   &TempRp, 0L, 0L, (LONG)FontWidth, (LONG)FontHeight, COPY);
  690.                 WaitBlit();
  691.                 if (interpret(TempRaster)) {
  692.                     fh = temp;
  693.                     break;
  694.                 }
  695.                 ++temp;
  696.             }
  697.         }
  698.  
  699.           /* Find out offsets within the window */
  700.         xoff = xl % fw;
  701.         yoff = yt % fh;
  702.  
  703.         if (cw) {
  704.             cw->xoff = xoff;
  705.             cw->yoff = yoff;
  706.             cw->fw = fw;
  707.             cw->fh = fh;
  708.             cw->font = font[fonts];
  709.         } else {
  710.             CacheWindow(window, xoff, yoff, fw, fh, font[fonts]);
  711.         }
  712.     }
  713.  
  714.       /* Set bounds */
  715.     minx = xoff;
  716.     maxx = minx +
  717.       (((GZZ ?
  718.         window->GZZWidth :
  719.         window->Width - window->BorderRight
  720.           /* Hack for borderless conman windows */
  721.         + (window->Flags & BORDERLESS && window->Flags & WINDOWSIZING ? 14 : 0))
  722.       - minx - fw) / fw) * fw;
  723.     maxy = yoff +
  724.       (((GZZ ? window->GZZHeight : window->Height) - yoff - fh) / fh) * fh;
  725.  
  726.       /* Check bounds */
  727.     if (xl > maxx) {
  728.         UnlockLayer(LockedLayer);
  729.         action = noaction;
  730.         return 0;
  731.     }
  732.       /* Set box dimensions */
  733.     xr = xl;
  734.     yb = yt;
  735.     ox = xr;
  736.     oy = yt;
  737.  
  738.       /* Select unit while starting */
  739.     starting = 1;
  740.  
  741.       /* Starting unit is character or frame */
  742.     Unit = SnapRsrc->StartUnit;
  743.     Ptrn = (SnapRsrc->CrawlPtrn ? SnapRsrc->CrawlPtrn : Pattern[Unit]);
  744.     OFType = 0L;
  745.     update_frame();
  746.  
  747.       /* Get the state machine running */
  748.     FOREVER {
  749.           /* Wait for something to happen */
  750.         REGISTER LONGBITS sig;
  751.  
  752.         MyTR.tr_time.tv_secs = 0;
  753.         MyTR.tr_time.tv_micro = 500000;
  754.         MyTR.tr_node.io_Command = TR_ADDREQUEST;
  755.         SendIO((struct IORequest *)&MyTR);
  756.  
  757.         sig = Wait(movesignal | cancelsignal | donesignal |
  758.           clicksignal | ticksignal | timersignal);
  759.  
  760.         if ((sig & timersignal) && CheckIO((struct IORequest *)&MyTR)) {
  761.             WaitIO((struct IORequest *)&MyTR);
  762.             erase_frame();
  763.             UnlockLayer(LockedLayer);   /* Unlock things */
  764.             sig = Wait(ticksignal);     /* Wait for input handler to become avtive */
  765.             LockLayer(0L, LockedLayer); /* Re-lock */
  766.               /* I guess I should check to see that the window is still
  767.                  there. Aw, what the heck. Apologies to anyone who gets
  768.                  bitten by this. */
  769.             DisplayBeep(NULL);
  770.             update_frame();
  771.         } else {
  772.             AbortIO((struct IORequest *)&MyTR);
  773.             WaitIO((struct IORequest *)&MyTR);
  774.             SetSignal(0, timersignal);
  775.         }
  776.  
  777.         if ((sig & ticksignal) && (SnapRsrc->CrawlPtrn != 0xffff)) {
  778.             crawl_frame(0L);
  779.         }
  780.  
  781.         mx = (LONG)(GZZ ? window->GZZMouseX : window->MouseX)
  782.           + window->RPort->Layer->Scroll_X;
  783.         if (mx < 0) {
  784.             mx = 0;
  785.         }
  786.           /* Calculate which edge is closest */
  787.         if ((mx - xl) < (xr - mx)) {
  788.             closex = closeleft;
  789.         } else {
  790.             closex = closeright;
  791.         }
  792.           /* Only interested in real char pos */
  793.         mx = mx - ((mx - xoff) % fw);
  794.  
  795.         my = (LONG)(GZZ ? window->GZZMouseY : window->MouseY)
  796.           + window->RPort->Layer->Scroll_Y;
  797.         if (my < 0) {
  798.             my = 0;
  799.         }
  800.           /* Calculate which row is closest */
  801.         if ((my - yt) < (yb - my)) {
  802.             closey = closetop;
  803.         } else {
  804.             closey = closebottom;
  805.         }
  806.         my = my - ((my - yoff) % fh);
  807.  
  808.           /* Hey, it moves! It's alive!! */
  809.         if ((sig & movesignal) && (action == snaptext)) {
  810.             if (mx != ox || my != oy) {  /* Something's happened */
  811.                 ExtendSelection();
  812.                 update_frame();
  813.                 starting = 0;
  814.                 ox = mx;
  815.                 oy = my;
  816.                 sig &= ~clicksignal;
  817.             }
  818.         }
  819.  
  820.           /* Ok, forget it... */
  821.         if (sig & cancelsignal) {
  822.             erase_frame();
  823.             UnlockLayer(LockedLayer);
  824.             return 0;
  825.         }
  826.  
  827.           /* Click */
  828.         if ((sig & clicksignal) && (action == snaptext)) {
  829.               /* Selecting unit */
  830.             if (starting) {
  831.                 if (mx == ox && my == oy) {
  832.                     ChangeUnit();
  833.                     if (Unit == UNIT_CHAR) {
  834.                         ChangeUnit();
  835.                     }
  836.                     update_frame();
  837.                 } else if (Unit == UNIT_FRAME) {
  838.                     ChangeUnit();
  839.                     update_frame();
  840.                 }
  841.             }
  842.             if (mx != ox || my != oy) { /* Click in a new place */
  843.                 ExtendSelection();
  844.                 update_frame();
  845.                 starting = 0;
  846.                 ox = mx;
  847.                 oy = my;
  848.             }
  849.         }
  850.  
  851.           /* Finished */
  852.         if (sig & donesignal) {
  853.             erase_frame();
  854.             return SnapChars();
  855.         }
  856.     }
  857. }
  858.  
  859. int MergePlanes(struct BitMap *src)
  860. {
  861.   register int width, height;
  862.   struct BitMap bm0, bm1;
  863.  
  864.   width  = src->BytesPerRow*8;
  865.   height = src->Rows;
  866.  
  867.   InitBitMap( &bm0,   1, width, height );
  868.   InitBitMap( &bm1,   1, width, height );
  869.  
  870.   bm0.Planes[0] = src->Planes[0];
  871.   bm1.Planes[0] = src->Planes[1];
  872.  
  873.   BltBitMap(
  874.             &bm1,     0,      0,     /* src, x0, y0 */
  875.             &bm0,     0,      0,     /* dest,x1, y1 */
  876.                   width, height,     /*      dx, dy */
  877.             0xee,                    /* minterm     */
  878.             0xff,                    /* planepick   */
  879.             0                        /* tempA       */
  880.            );
  881.  return 0;
  882. }
  883.  
  884.  
  885.