home *** CD-ROM | disk | FTP | other *** search
/ Atari FTP / ATARI_FTP_0693.zip / ATARI_FTP_0693 / Mint / toswinsc.zoo / util.c < prev    next >
C/C++ Source or Header  |  1992-10-27  |  20KB  |  892 lines

  1. /*
  2.  * Copyright 1992 Eric R. Smith. All rights reserved.
  3.  * Redistribution is permitted only if the distribution
  4.  * is not for profit, and only if all documentation
  5.  * (including, in particular, the file "copying")
  6.  * is included in the distribution in unmodified form.
  7.  * THIS PROGRAM COMES WITH ABSOLUTELY NO WARRANTY, NOT
  8.  * EVEN THE IMPLIED WARRANTIES OF MERCHANTIBILITY OR
  9.  * FITNESS FOR A PARTICULAR PURPOSE. USE AT YOUR OWN
  10.  * RISK.
  11.  */
  12. #include "xgem.h"
  13. #include <string.h>
  14. #include <stdlib.h>
  15. #include "toswin.h"
  16. #include "twdefs.h"
  17. #include "twproto.h"
  18.  
  19. extern char *read_scrap();
  20. extern void write_scrap();
  21.  
  22. /* shift key states */
  23. #define KLSHIFT    0x1
  24. #define KRSHIFT    0x2
  25. #define KCTRL    0x4
  26. #define KALT    0x8
  27. #define KANY    (0xf)
  28.  
  29. /* what to add at the end of lines */
  30. #define CR    1
  31. #define LF    2
  32. #define CRLF    3
  33. #ifdef NONE
  34. #undef NONE
  35. #endif
  36.  
  37. #define NONE    0
  38. int paste_options = CR;
  39.  
  40. /* how to cut lines */
  41. #define STRIPBLANKS    1
  42. #define OBEYLINES    2
  43. int cut_options = STRIPBLANKS;
  44.  
  45.  
  46. void
  47. setcutoptions()
  48. {
  49.     int xclip, yclip, wclip, hclip;
  50.     int ret;
  51.  
  52.     cutdialog[ADDCRLF].ob_state = 
  53.     cutdialog[ADDLF].ob_state =
  54.     cutdialog[ADDCR].ob_state = 
  55.     cutdialog[ADDNONE].ob_state = NORMAL;
  56.  
  57.     switch(paste_options) {
  58.     case CR:
  59.         ret = ADDCR; break;
  60.     case LF:
  61.         ret = ADDLF; break;
  62.     case CRLF:
  63.         ret = ADDCRLF; break;
  64.     default:
  65.         ret = NONE; break;
  66.     }
  67.     cutdialog[ret].ob_state = SELECTED;
  68.  
  69.     cutdialog[STRIPEOL].ob_state = (cut_options & STRIPBLANKS) ? SELECTED :
  70.             NORMAL;
  71.     cutdialog[OBEYEOL].ob_state = (cut_options & OBEYLINES) ? SELECTED :
  72.             NORMAL;
  73.  
  74.     wind_update(1);
  75.     form_center(cutdialog, &xclip, &yclip, &wclip, &hclip);
  76.     form_dial(FMD_START, 0, 0, 32, 32, xclip, yclip, wclip, hclip);
  77.     if (win_flourishes)
  78.         form_dial(FMD_GROW, 0, 0, 32, 32, xclip, yclip, wclip, hclip);
  79.     objc_draw(cutdialog, 0, 2, xclip, yclip, wclip, hclip);
  80.     ret = form_do(cutdialog,  0);
  81.     if (win_flourishes)
  82.         form_dial(FMD_SHRINK, 0, 0, 32, 32, xclip, yclip, wclip, hclip);
  83.     form_dial(FMD_FINISH, 0, 0, 32, 32, xclip, yclip, wclip, hclip);
  84.     wind_update(0);
  85.  
  86.     cutdialog[ret].ob_state = NORMAL;
  87.     if (ret == EDOK) {
  88.         cut_options = NONE;
  89.         if (cutdialog[STRIPEOL].ob_state == SELECTED)
  90.             cut_options |= STRIPBLANKS;
  91.         if (cutdialog[OBEYEOL].ob_state == SELECTED)
  92.             cut_options |= OBEYLINES;
  93.  
  94.         if (cutdialog[ADDCR].ob_state == SELECTED)
  95.             paste_options = CR;
  96.         else if (cutdialog[ADDLF].ob_state == SELECTED)
  97.             paste_options = LF;
  98.         else if (cutdialog[ADDCRLF].ob_state == SELECTED)
  99.             paste_options = CRLF;
  100.         else
  101.             paste_options = NONE;
  102.  
  103.     }
  104. }
  105.  
  106. /* unselect all text in the indicated window */
  107.  
  108. void
  109. unselect(t)
  110.     TEXTWIN *t;
  111. {
  112.     int i, j;
  113.  
  114.     for (i = 0; i < t->maxy; i++)
  115.         for (j = 0; j < t->maxx; j++) {
  116.             if (t->cflag[i][j] & CSELECTED) {
  117.                 t->cflag[i][j] &= ~CSELECTED;
  118.                 t->cflag[i][j] |= CTOUCHED;
  119.                 t->dirty[i] |= SOMEDIRTY;
  120.                 }
  121.         }
  122.     refresh_textwin(t);
  123. }
  124.  
  125. /* cut selected text from a window */
  126.  
  127. char *cliptext = 0;
  128.  
  129. void
  130. cut(w)
  131.     WINDOW *w;
  132. {
  133.     TEXTWIN *t;
  134.     int i, j, numchars, numlines;
  135.     int linedone;
  136.     int needcrlf;
  137.     char *s, c;
  138.  
  139.     if (w->wtype != TEXT_WIN) return;
  140.     t = w->extra;
  141.  
  142.     if (cliptext) {
  143.         free(cliptext);
  144.         cliptext = 0;
  145.     }
  146.  
  147.     numchars = numlines = 0;
  148.     for (i = 0; i < t->maxy; i++) {
  149.         linedone = 0;
  150.         for (j = 0; j < t->maxx; j++) {
  151.             if (t->cflag[i][j] & CSELECTED) {
  152.                 numchars++;
  153.                 if (!linedone) {
  154.                     numlines++;
  155.                     linedone = 1;
  156.                 }
  157.             }
  158.         }
  159.     }
  160.     if (!numchars) {
  161.         form_alert(1, AlertStrng(NOTEXT));
  162.         return;
  163.     }
  164. /*
  165.  * The cut strategy is a little complicated, but here it is:
  166.  * A "line" is a continuous stream of characters. If the "Obey Lines"
  167.  * option is set, lines always end at end-of-line; otherwise, they
  168.  * end at eol only if there are 2 or more spaces after them.
  169.  * If "Strip Blanks" is set, then any trailing blanks are deleted.
  170.  */
  171.     cliptext = malloc(numchars+numlines+numlines+1);
  172.     if (!cliptext) {
  173.         form_alert(1, AlertStrng(NOMEM));
  174.         return;
  175.     }
  176.  
  177.     s = cliptext;
  178.  
  179.     needcrlf = 0;
  180.     for (i = 0; i < t->maxy; i++) {
  181.         linedone = 0;
  182.         for (j = 0; j < t->maxx; j++) {
  183.             if (t->cflag[i][j] & CSELECTED) {
  184.                 c = t->data[i][j];
  185.                 if (!c) c = ' ';
  186.                 *s++ = c;
  187.                 needcrlf = 1;
  188.                 if ( (cut_options & OBEYLINES) ||
  189.                      (j < t->maxy-2) ||
  190.                      ((c == ' ') && t->data[i][j-1] == ' '))
  191.                     linedone = 1;
  192.                 else
  193.                     linedone = 0;
  194.             }
  195.         }
  196.         if (linedone) {
  197.             if (cut_options & STRIPBLANKS) {
  198.                 while (s > cliptext && s[-1] == ' ')
  199.                     --s;
  200.             }
  201.             *s++ = '\r'; *s++ = '\n';
  202.             needcrlf = 0;
  203.         }
  204.     }
  205.  
  206. /* tie off cliptext */
  207.     if (needcrlf) {
  208.         *s++ = '\r'; *s++ = '\n';
  209.     }
  210.     *s++ = 0;
  211.  
  212.     unselect(t);
  213. }
  214.  
  215. /* paste text into a window */
  216.  
  217. void
  218. paste(w)
  219.     WINDOW *w;
  220. {
  221.     char *s;
  222.     int c;
  223.  
  224.     if (!cliptext) {
  225.         form_alert(1, AlertStrng(NOCUT));
  226.         return;
  227.     }
  228.     for (s = cliptext; *s; s++) {
  229.         c = *(unsigned char *)s;
  230.         if (c == '\r' && s[1] == '\n') {
  231.             s++;
  232.             switch(paste_options) {
  233.             case CRLF:
  234.                 (*w->keyinp)(w, '\r', 0);
  235.             case LF:
  236.                 (*w->keyinp)(w, '\n', 0);
  237.                 break;
  238.             case CR:
  239.                 (*w->keyinp)(w, '\r', 0);
  240.                 break;
  241.             case NONE:
  242.                 break;
  243.             }
  244.         } else 
  245.             (*w->keyinp)(w, c, 0);
  246.     }
  247. }
  248.  
  249. void
  250. redraw_screen(x, y, w, h)
  251.     int x, y, w, h;
  252. {
  253.     form_dial(0, x, y, w, h, x, y, w, h);
  254.     form_dial(3, x, y, w, h, x, y, w, h);
  255. }
  256.  
  257. /* cut text from the desktop */
  258.  
  259. void
  260. cut_from_desk(x, y)
  261.     int x, y;
  262. {
  263.     int i;
  264.     int width, height, x1, y1, x2, y2, dummy;
  265.     WINDOW *w;
  266.  
  267.     i = objc_find(deskobj, 0, 1, x, y);
  268.     if (i != CLIPICN) {
  269.         if (gl_topwin && gl_topwin->wtype == TEXT_WIN)
  270.             unselect(gl_topwin->extra);
  271.         return;
  272.     }
  273.     width = deskobj[i].ob_width; height = deskobj[i].ob_height;
  274.     objc_offset(deskobj, i, &x1, &y1);
  275.  
  276. /* drag the icon around */
  277.     wind_update(BEG_MCTRL);
  278.     graf_mouse(FLAT_HAND, 0L);
  279.     graf_dragbox(width, height, x1, y1, xdesk, ydesk, wdesk, hdesk,
  280.         &x2, &y2);
  281.  
  282.     graf_mkstate(&x, &y, &dummy, &dummy);
  283.     graf_mouse(ARROW, 0L);
  284.     wind_update(END_MCTRL);
  285.  
  286. /* did we actually move anywhere? */
  287.     if (x >= x1 && x <= x1+width && y >= y1 && y <= y1+height) {
  288.         return;
  289.     }
  290.     w = find_window(x, y);
  291.     if (w && w->wtype == TEXT_WIN) {
  292.         if (cliptext)
  293.             free(cliptext);
  294.  
  295.         cliptext = read_scrap("SCRAP.TXT");
  296.         if (!cliptext) {
  297.             form_alert(1, AlertStrng(SCRAPDAT));
  298.             return;
  299.         }
  300.         paste(w);
  301. #if 0
  302.     } else {        /* just move the icon */
  303.         hide_mouse();
  304.         deskobj[i].ob_x += x2 - x1;
  305.         deskobj[i].ob_y += y2 - y1;
  306.         redraw_screen(x1, y1, width, height);
  307.         redraw_screen(x2, y2, width, height);
  308.         show_mouse();
  309. #endif
  310.     }
  311. }
  312.  
  313. /* paste text onto the desktop */
  314.  
  315. void
  316. paste_to_desk(x, y)
  317.     int x, y;
  318. {
  319.     int i;
  320.     int x1, y1;
  321.     WINDOW *w;
  322.  
  323.     w = find_window(x, y);
  324.     i = objc_find(deskobj, 0, 1, x, y);
  325.     if (i == CLIPICN) {
  326.         objc_offset(deskobj, CLIPICN, &x1, &y1);
  327.         objc_change(deskobj, CLIPICN, 0, xdesk, ydesk, wdesk, hdesk,
  328.             SELECTED, 0);
  329.         if (w == toolwindow) {
  330.             redraw_window(toolwindow, x1, y1,
  331.                 deskobj[i].ob_width, deskobj[i].ob_height);
  332.         }
  333.         write_scrap("SCRAP.TXT", cliptext, (int)strlen(cliptext));
  334.         objc_change(deskobj, CLIPICN, 0, xdesk, ydesk, wdesk, hdesk,
  335.             NORMAL, 0);
  336.         if (w == toolwindow) {
  337.             redraw_window(toolwindow, x1, y1,
  338.                 deskobj[i].ob_width, deskobj[i].ob_height);
  339.         }
  340.     }
  341. }
  342.  
  343. static void
  344. lightbox(plin, numpoints)
  345.     int *plin;
  346.     int numpoints;
  347. {
  348.     static int vtbl[4] = { 0x5555, 0xaaaa, 0xaaaa, 0x5555 };
  349.     static int htbl[2] = { 0x5555, 0xaaaa };
  350.     int style, *linexy, i;
  351.     int attrib[6];
  352.  
  353.     vql_attribute(vdi_handle, attrib);
  354.  
  355.     vsl_color(vdi_handle, 1);
  356.  
  357.     for (i = 1; i < numpoints; i++) {
  358.         if (plin[0] == plin[2])
  359.             style = vtbl[(plin[0] & 1) | ((plin[1] & 1) << 1)];
  360.         else {
  361.             linexy = (plin[0] < plin[2]) ? plin : plin+2;
  362.             style = htbl[ linexy[1] & 1 ];
  363.         }
  364.         vsl_udsty(vdi_handle, style);
  365.         vsl_type(vdi_handle, 7);
  366.         v_pline(vdi_handle, 2, plin);
  367.         plin += 2;
  368.     }
  369.  
  370.     vsl_type(vdi_handle, attrib[0]);
  371.     vsl_color(vdi_handle, attrib[1]);
  372. }
  373.  
  374. void
  375. hot_dragbox(plin, numpoints, lastx, lasty)
  376.     int *plin;
  377.     int numpoints;
  378.     int *lastx, *lasty;
  379. {
  380.     int boxx, boxy;
  381.     int msx, msy, mbutton, dummy, event;
  382.     int newx, newy;
  383.     int oldbx, oldby;
  384.     int deltax, deltay;
  385.     int width, height;
  386.     int clipx, clipy, clipw, cliph;    /* box holding the clipboard
  387.                            icon */
  388.  
  389.     int inclip = 0;
  390.     int i;
  391.  
  392. /* find the biggest rectangle that will enclose the region */
  393.     boxx = plin[0]; boxy = plin[1];
  394.     clipx = boxx; clipy = boxy;
  395.  
  396.     for (i = 2; i < numpoints + numpoints; i += 2) {
  397.         if (plin[i] < boxx) boxx = plin[i];
  398.         if (plin[i] > clipx) clipx = plin[i];
  399.         if (plin[i+1] < boxy) boxy = plin[i+1];
  400.         if (plin[i+1] > clipy) clipy = plin[i+1];
  401.     }
  402.     width = clipx - boxx + 1;
  403.     height = clipy - boxy + 1;
  404.  
  405.     set_wrmode(3);        /* XOR */
  406.  
  407.     if (showtools) {
  408.         objc_offset(deskobj, CLIPICN, &clipx, &clipy);
  409.         clipw = deskobj[CLIPICN].ob_width;
  410.         cliph = deskobj[CLIPICN].ob_height;
  411.  
  412.         graf_mkstate(&msx, &msy, &mbutton, &dummy);
  413.         if (msx >= clipx && msx < clipx+clipw && 
  414.             msy >= clipy && msy < clipy+cliph)
  415.             inclip = 1;
  416.     } else {
  417.         graf_mkstate(&msx, &msy, &mbutton, &dummy);
  418.         clipx = clipy = clipw = cliph = -1;
  419.         inclip = 0;
  420.     }
  421.  
  422.     hide_mouse();
  423.     lightbox(plin, numpoints);
  424.     show_mouse();
  425.  
  426.     reset_clip();
  427.     for(;;) {
  428.         oldbx = boxx; oldby = boxy;
  429.         event = evnt_multi(MU_BUTTON|MU_M1|MU_M2,
  430.             1, 0x0001, 0x0000,
  431.             1, msx, msy, 1, 1,
  432.             inclip, clipx, clipy, clipw, cliph,
  433.             0L, 0L,
  434.             &newx, &newy, &mbutton, &dummy,
  435.             &dummy, &dummy);
  436.         if (showtools && (event & MU_M2)) {
  437.             inclip = !inclip;
  438.             hide_mouse();
  439.             lightbox(plin, numpoints);
  440.             objc_change(deskobj, CLIPICN, 0, clipx, clipy, clipw,
  441.                 cliph, inclip ? SELECTED : NORMAL, 0);
  442.             redraw_window(toolwindow, clipx, clipy,
  443.                 clipw, cliph);
  444. /* note: redraw_window turns the mouse back on and changes the clipping
  445.  * rectangle
  446.  */
  447.             reset_clip();
  448.             hide_mouse();
  449.             lightbox(plin, numpoints);
  450.             show_mouse();
  451.         }
  452.         if (event & MU_M1) {
  453.             boxx = boxx + (newx - msx);
  454.             if (boxx < xdesk)
  455.                 boxx = xdesk;
  456.             else if (boxx + width > xdesk + wdesk)
  457.                 boxx = xdesk+wdesk - width;
  458.             boxy = boxy + (newy - msy);
  459.             if (boxy < ydesk)
  460.                 boxy = ydesk;
  461.             else if (boxy + height > ydesk + hdesk)
  462.                 boxy = ydesk + hdesk - height;
  463.             if (oldbx != boxx || oldby != boxy) {
  464.                 hide_mouse();
  465.                 lightbox(plin, numpoints);
  466.                 deltax = boxx - oldbx;
  467.                 deltay = boxy - oldby;
  468.                 for (i = 0; i < numpoints + numpoints; i += 2) {
  469.                     plin[i] += deltax;
  470.                     plin[i+1] += deltay;
  471.                 }
  472.                 lightbox(plin, numpoints);
  473.                 oldbx = boxx;
  474.                 oldby = boxy;
  475.                 show_mouse();
  476.             } 
  477.         }
  478.         msx = newx;
  479.         msy = newy;
  480.         if (event & MU_BUTTON)
  481.             break;
  482.     }
  483.     hide_mouse();
  484.     lightbox(plin, numpoints);
  485.     show_mouse();
  486.     *lastx = boxx;
  487.     *lasty = boxy;
  488. }
  489.  
  490. /*
  491.  * debounce the mouse, so that we can distinguish single-clicks, double-clicks,
  492.  * and drags
  493.  */
  494.  
  495. static int
  496. debounce(time, x, y, kshift, buttons)
  497.     long time;
  498.     int *x, *y, *kshift, *buttons;
  499. {
  500.     int clicks = 0;
  501.     int event, dummy;
  502.  
  503.     if (time > 0) {
  504.         event = evnt_multi(MU_BUTTON | MU_TIMER,
  505.             0x0102, 0x0003, *buttons,
  506.             0, 0, 0, 0, 0,
  507.             0, 0, 0, 0, 0,
  508.             (void *)0,
  509.             time,        /* milliseconds */
  510.             x, y, buttons, kshift,
  511.             &dummy, &clicks);
  512.     } else {
  513.         event = MU_TIMER;
  514.     }
  515.     graf_mkstate(x, y, buttons, kshift);
  516.  
  517.     return (event & MU_BUTTON) ? clicks : 1;
  518. }
  519.  
  520. #ifdef GLOBAL_APPL_MENUS
  521.  
  522. void
  523. togglemenu()
  524. {
  525.     WINDOW *w = gl_topwin;
  526.     ENTRY *e;
  527.  
  528.     for (e = globalmenu->contents; e; e = e->next) {
  529.         if (e->func == togglemenu) {
  530.             break;
  531.         }
  532.     }
  533.  
  534.     if (!sys_menu) {
  535.         sys_menu = 1;
  536.         appl_menus = 0;
  537.         show_menu(sysbar);
  538.     } else {
  539.         appl_menus = !appl_menus;
  540.         if (w && w->wtype == TEXT_WIN) {
  541.             if (w->menu && appl_menus) {
  542.                 sys_menu = 0;
  543.                 show_menu(w->menu);
  544.             }
  545.         }
  546.     }
  547.     if (e) {
  548.         if (appl_menus)
  549.             check_entry(globalmenu, e);
  550.         else
  551.             uncheck_entry(globalmenu, e);
  552.     }
  553. }
  554.  
  555. #endif
  556.  
  557. static void pixpoint __PROTO((TEXTWIN *, int, int, int *, int *));
  558. static void dragtext __PROTO((TEXTWIN *, int, int));
  559. static void selectfrom __PROTO((TEXTWIN *, int, int, int, int));
  560. static void select __PROTO((TEXTWIN *, int, int, int));
  561.  
  562. static void
  563. pixpoint(t, col, row, xp, yp)
  564.     TEXTWIN *t;
  565.     int col, row, *xp, *yp;
  566. {
  567.     int x, y;
  568.     WINDOW *w = t->win;
  569.  
  570.     char2pixel(t, col, row, &x, &y);
  571.  
  572.     if (x < w->wi_x)
  573.         x = w->wi_x;
  574.     else if (x > w->wi_x + w->wi_w)
  575.         x = w->wi_x + w->wi_w;
  576.  
  577.     if (y < w->wi_y)
  578.         y = w->wi_y;
  579.     else if (y > w->wi_y + w->wi_h)
  580.         y = w->wi_y + w->wi_h;
  581.  
  582.     *xp = x;
  583.     *yp = y;
  584. }
  585.  
  586. static void
  587. dragtext(t, x, y)
  588.     TEXTWIN *t;
  589.     int x, y;
  590. {
  591.     static int plin[20];
  592.     int numpoints;
  593.     int i, j;
  594.     int firstx, firsty, lastx, lasty;
  595.     WINDOW *newwin, *w = t->win;
  596.     int buttons, kshift;
  597.  
  598.     firstx = firsty = lastx = lasty = -1;
  599.     /* find edges of region */
  600.     for (j = 0; j < t->maxy; j++) {
  601.         for (i = 0; i < t->maxx; i++) {
  602.             if (t->cflag[j][i] & CSELECTED) {
  603.                 if (firstx == -1) {
  604.                     firstx = i;
  605.                     firsty = j;
  606.                 }
  607.                 lastx = i;
  608.                 lasty = j;
  609.             }
  610.         }
  611.     }
  612.  
  613.     if (firstx == -1) return;
  614.  
  615.     pixpoint(t, firstx, firsty, &plin[0], &plin[1]);
  616.  
  617.     if (firsty == lasty) {
  618.         numpoints = 5;
  619.         pixpoint(t, lastx+1, firsty, &plin[2], &plin[3]);
  620.         plin[4] = plin[2]; plin[5] = plin[3] + t->cheight;
  621.         if (plin[5] > w->wi_y + w->wi_h)
  622.             plin[5] = w->wi_y + w->wi_h;
  623.         plin[6] = plin[0]; plin[7] = plin[5];
  624.         plin[8] = plin[0]; plin[9] = plin[1];
  625.     } else {
  626.         numpoints = 9;
  627.         pixpoint(t, t->maxx, firsty, &plin[2], &plin[3]);
  628.         pixpoint(t, t->maxx, lasty, &plin[4], &plin[5]);
  629.         pixpoint(t, lastx+1, lasty, &plin[6], &plin[7]);
  630.         plin[8] = plin[6]; plin[9] = plin[7] + t->cheight;
  631.         if (plin[9] > w->wi_y + w->wi_h)
  632.             plin[9] = w->wi_y + w->wi_h;
  633.         plin[10] = w->wi_x; plin[11] = plin[9];
  634.         pixpoint(t, 0, firsty+1, &plin[12], &plin[13]);
  635.         plin[14] = plin[0]; plin[15] = plin[13];
  636.         plin[16] = plin[0]; plin[17] = plin[1];
  637.     }
  638.  
  639. /* drag text */
  640.     wind_update(BEG_MCTRL);
  641.     graf_mouse(FLAT_HAND, 0L);
  642.     hot_dragbox(plin, numpoints, &x, &y);
  643.     graf_mkstate(&x, &y, &buttons, &kshift);
  644.     graf_mouse(ARROW, 0L);
  645.     wind_update(END_MCTRL);
  646. /* did we actually move anywhere? */
  647.     newwin = find_window(x, y);
  648.     if (newwin == t->win) {
  649.         pixel2char(t, x, y, &x, &y);
  650.         if (t->cflag[y][x] & CSELECTED)
  651.             return;
  652.     }
  653.  
  654. /* yes, we did move; do a cut and paste */
  655.     cut(w);
  656.     if (newwin) {
  657.         if (newwin->wtype == TEXT_WIN)
  658.             paste(newwin);
  659.         else
  660.             paste_to_desk(x, y);
  661.     } else {
  662.         form_alert(1, AlertStrng(NOTDESK)); 
  663.     }
  664. }
  665.  
  666. static void
  667. selectfrom(t, x1, y1, x2, y2)
  668.     TEXTWIN *t;
  669.     int x1, y1, x2, y2;
  670. {
  671.     int i, j;
  672.     int first, last;
  673.  
  674. /* first, normalize coordinates */
  675.     if ( (y1 > y2) || (y1 == y2 && x1 > x2) ) {
  676.         i = x1; j = y1;
  677.         x1 = x2; y1 = y2;
  678.         x2 = i; y2 = j;
  679.     }
  680.  
  681.     for (j = 0; j <= y1; j++) {
  682.         last = (j == y1) ? x1 : t->maxx;
  683.         for (i = 0; i < last; i++) {
  684.             if (t->cflag[j][i] & CSELECTED) {
  685.                 t->cflag[j][i] &= ~CSELECTED;
  686.                 t->cflag[j][i] |= CTOUCHED;
  687.                 t->dirty[j] |= SOMEDIRTY;
  688.             }
  689.         }
  690.     }
  691.     for (j = y1; j <= y2; j++) {
  692.         first = (j == y1) ? x1 : 0;
  693.         last = (j == y2) ? x2+1 : t->maxx;
  694.         for (i = first; i < last; i++) {
  695.             if (!(t->cflag[j][i] & CSELECTED)) {
  696.                 t->cflag[j][i] |= (CTOUCHED|CSELECTED);
  697.                 t->dirty[j] |= SOMEDIRTY;
  698.             }
  699.         }
  700.     }
  701.     for (j = y2; j < t->maxy; j++) {
  702.         first = (j == y2) ? x2+1 : 0;
  703.         for (i = first; i < t->maxx; i++) {
  704.             if (t->cflag[j][i] & CSELECTED) {
  705.                 t->cflag[j][i] &= ~CSELECTED;
  706.                 t->cflag[j][i] |= CTOUCHED;
  707.                 t->dirty[j] |= SOMEDIRTY;
  708.             }
  709.         }
  710.     }
  711.     refresh_textwin(t);
  712. }
  713.  
  714. void
  715. select(t, curcol, currow, kshift)
  716.     TEXTWIN *t;
  717.     int curcol, currow, kshift;
  718. {
  719.     WINDOW *v = t->win;
  720.     int x, y, firstx, firsty;
  721.     int event, dummy, msx, msy, mbutton;
  722.     int anchorcol, anchorrow;
  723.     short *WIDE = t->cwidths;
  724.     int cboxw;
  725.  
  726.     refresh_textwin(t);
  727.  
  728. /* shift+select adds to existing text; regular select replaces */
  729.     anchorrow = currow; anchorcol = curcol;
  730.  
  731.     if (kshift & 3) {
  732.         for (y = 0; y < t->maxy; y++)
  733.             for (x = 0; x < t->maxx; x++) {
  734.                 if (t->cflag[y][x] & CSELECTED) {
  735.                     anchorrow = y;
  736.                     anchorcol = x;
  737.                     if (y < currow ||
  738.                         (y == currow && x < curcol)) {
  739.                         goto foundselect;
  740.                     }
  741.                         
  742.                 }
  743.             }
  744.     } else {
  745.         unselect(t);
  746.     }
  747.  
  748. foundselect:
  749.  
  750.     char2pixel(t, curcol, currow, &x, &y);
  751.     firstx = msx = x; firsty = msy = y;
  752.  
  753.     wind_update(BEG_MCTRL);
  754.     graf_mouse(POINT_HAND, 0L);
  755.  
  756.     selectfrom(t, anchorcol, anchorrow, curcol, currow);
  757.  
  758.     cboxw = t->cmaxwidth;
  759.     for(;;) {
  760.         if (WIDE)
  761.             cboxw = WIDE[t->data[currow][curcol]];
  762.  
  763.         event = evnt_multi(MU_M1 | MU_BUTTON, 
  764.             0x101, 0x0003, 0x0001,
  765.             1, x, y, cboxw, t->cheight,
  766.             0, 0, 0, 0, 0,
  767.             0L, 0L,
  768.             &msx, &msy, &mbutton, &dummy,
  769.             &dummy, &dummy);
  770.         if (event & MU_M1) {
  771.             if (msx < v->wi_x)
  772.                 msx = v->wi_x;
  773.             else if (msx >= v->wi_x + v->wi_w)
  774.                 msx = v->wi_x + v->wi_w - 1;
  775.             if (msy < v->wi_y)
  776.                 msy = v->wi_y;
  777.             else if (msy >= v->wi_y + v->wi_h)
  778.                 msy = v->wi_y + v->wi_h - 1;
  779.             pixel2char(t, msx, msy, &curcol, &currow);
  780.             char2pixel(t, curcol, currow, &x, &y);
  781.             selectfrom(t, anchorcol, anchorrow, curcol, currow);
  782.         }
  783.         if (event & MU_BUTTON)
  784.             break;
  785.     }
  786.  
  787.     graf_mouse(ARROW, 0L);
  788.     wind_update(END_MCTRL);
  789.  
  790.     if ( ((msx - firstx) < 3) && ((msx - firstx) > -3) &&
  791.          ((msy - firsty) < 3) && ((msy - firsty > -3)) ) {
  792.         unselect(t);
  793.         return;
  794.     }
  795. }
  796.  
  797. #define BOXSIZE 8
  798.  
  799. int
  800. win_ctrl(v, x, y)
  801.     WINDOW *v;
  802.     int x, y;
  803. {
  804.     int wx, wy, ww, wh;
  805.  
  806.     wind_update(BEG_MCTRL);
  807.     wind_get(v->wi_handle, WF_CURRXYWH, &wx, &wy, &ww, &wh);
  808.  
  809.     if ((x >= v->wi_x + v->wi_w - BOXSIZE) &&
  810.         (y >= v->wi_y + v->wi_h - BOXSIZE)) {
  811.         graf_mouse(POINT_HAND, 0L);
  812.         graf_rubberbox(wx, wy, 8, 8, &ww, &wh);
  813.         (*v->sized)(v, wx, wy, ww, wh);
  814.     } else if ((x >= v->wi_x + v->wi_w - BOXSIZE) &&
  815.            (y <= v->wi_y + BOXSIZE) ) {
  816.         do {
  817.             graf_mkstate(&x, &y, &ww, &wh);
  818.         } while (ww);
  819.         (*v->fulled)(v);
  820.     } else {
  821.         graf_mouse(FLAT_HAND, 0L);
  822.         graf_dragbox(ww, wh, wx, wy, xdesk, ydesk, wdesk, hdesk,
  823.             &wx, &wy);
  824.         (*v->moved)(v, wx, wy, ww, wh);
  825.     }
  826.     graf_mouse(ARROW, 0L);
  827.     wind_update(END_MCTRL);
  828.     return 1;
  829. }
  830.  
  831. int
  832. win_click(w, clicks, x, y, kshift, buttons)
  833.     WINDOW *w;
  834.     int clicks, x, y, kshift, buttons;
  835. {
  836.     TEXTWIN *t;
  837.     int x1, y1;
  838.     int i, j;
  839.     int ret = 0;
  840.  
  841.     t = w->extra;
  842.     
  843.     if (clicks == 1)
  844.         clicks = debounce(300L - gl_timer, &x, &y, &i, &j);
  845.  
  846.     if (clicks == 1 && buttons == 1) {  /* left click */
  847.     /* is the button still down?; if so, select some text */
  848.         graf_mkstate(&x, &y, &buttons, &kshift);
  849.         if (buttons != 1 && !(kshift&(KLSHIFT|KRSHIFT))) {
  850.     /* just a single click -- unselect old text */
  851.             unselect(t);
  852.             return 1;
  853.         }
  854.         if (kshift & KCTRL) {
  855.             return win_ctrl(w, x, y);
  856.         }
  857.     /* convert to character coordinates */
  858.         pixel2char(t, x, y, &x1, &y1);
  859.  
  860.         if (t->cflag[y1][x1] & CSELECTED) {
  861.             dragtext(t, x1, y1);
  862.         } else {
  863.             select(t, x1, y1, kshift);
  864.         }
  865.         return 1;
  866. #ifdef GLOBAL_APPL_MENUS
  867.     } else if (buttons == 2) {
  868.         togglemenu();
  869.         ret = 1;
  870. #endif
  871.     }
  872.  
  873.     return ret;
  874. }
  875.  
  876. void
  877. desk_mouse(clicks, x, y, kshift, buttons)
  878.     int clicks, x, y, kshift, buttons;
  879. {
  880.     if (clicks == 1 && buttons == 1) {  /* left click */
  881.     /* is the button still down?; if so, select some text */
  882.         graf_mkstate(&x, &y, &buttons, &kshift);
  883.         if (buttons == 1) {    /* still down */
  884.             cut_from_desk(x, y);
  885.         }
  886. #ifdef GLOBAL_APPL_MENUS
  887.     } else if (buttons == 2) {    /* right mouse click */
  888.         togglemenu();
  889. #endif
  890.     }
  891. }
  892.