home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Libraries / stdwin / Packs / vt / vtselect.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-10-18  |  9.4 KB  |  388 lines  |  [TEXT/????]

  1. /* Copy and paste operations for VT.
  2.    The selections here are not rectangles,
  3.    like in most other vt-stuff */
  4.  
  5. /* XXX This must be redesigned.
  6.    In the new design, the event loop is in the caller and we remember
  7.    the state somehow in the vt structure.
  8.    This is necessary to make it independent of aterm (special semantics
  9.    of WE_EXTERN events) and to support extending the selection with the
  10.    third button.
  11. */
  12.  
  13. #include "vtimpl.h"
  14.  
  15.  
  16. extern int extra_downs; /* For aterm */
  17.  
  18.  
  19. /* Data structure used by coord_sort */
  20.  
  21. struct coord {        /* A coordinate */
  22.     int c, r;    /* Column and row */
  23. };
  24.  
  25. /*
  26.  *    Bubblesort an array of coordinates.
  27.  */
  28. static void
  29. coord_sort(coord, n)
  30.     struct coord coord[];
  31.     int n;
  32. {
  33.     int i, j, big;
  34.     /* Bubble */
  35.     for (j = n; --j > 0; ) {
  36.     /* Find biggest in 0..j */
  37.     for (big = i = 0; ++i <= j; ) { /* Compare big and i */
  38.         if (coord[big].r < coord[i].r ||
  39.         (coord[big].r == coord[i].r && coord[big].c < coord[i].c))
  40.         big = i; /* Found a bigger one */
  41.     }
  42.     if (big != j) {
  43.         struct coord swap;
  44.         swap = coord[big]; coord[big] = coord[j]; coord[j] = swap;
  45.     }
  46.     }
  47. }
  48.  
  49. /*
  50.  *    Delete double occurences in a sorted
  51.  *    array of coordinates (Both of them!)
  52.  */
  53. static int
  54. no_double(coord, n)
  55.     struct coord coord[];
  56.     int n;
  57. {
  58.     int i, j;
  59.     for (i = j = 0; i < n; ) {
  60.     if (i < n - 1 && coord[i].r == coord[i + 1].r
  61.     && coord[i].c == coord[i + 1].c) {
  62.         i += 2; /* Skip both */
  63.     }
  64.     else {
  65.         if (i != j) coord[j] = coord[i]; /* Copy */
  66.         ++i; ++j;
  67.     }
  68.     }
  69.     return j; /* Return # array elements */
  70. }
  71.  
  72. /*
  73.  *    Set the selection of a vt, update state variables
  74.  */
  75. static void
  76. set_selection(vt, row1, col1, row2, col2)
  77.     VT *vt;
  78.     int row1, col1, row2, col2;
  79. {
  80.     /* Screen coordinates of begins/ends of selection */
  81.     struct coord coord[4];
  82.     int n_coord, i;
  83.  
  84.     /* Above last remembered line; repair */
  85.     if (row1 < -vt->topterm) {
  86.         row1 = -vt->topterm;
  87.         col1 = 0;
  88.     }
  89.  
  90.     /* Initialise array */
  91.     coord[0].r = vt->sel_row1;
  92.     coord[0].c = vt->sel_col1;
  93.     coord[1].r = vt->sel_row2;
  94.     coord[1].c = vt->sel_col2;
  95.     coord[2].r = row1;
  96.     coord[2].c = col1;
  97.     coord[3].r = row2;
  98.     coord[3].c = col2;
  99.  
  100.     /* Sort, optimise */
  101.     coord_sort(coord, 4);
  102.     n_coord = no_double(coord, 4);
  103.  
  104.     /* Blit */
  105.     if (n_coord > 0) {
  106.     VTBEGINDRAWING(vt);
  107.     for (i = 0; i < n_coord; i += 2)
  108.         vtinvert(vt, coord[i].r, coord[i].c, coord[i+1].r, coord[i+1].c);
  109.     VTENDDRAWING(vt);
  110.     }
  111.  
  112.     /* Save state */
  113.     vt->sel_row1 = row1;
  114.     vt->sel_col1 = col1;
  115.     vt->sel_row2 = row2;
  116.     vt->sel_col2 = col2;
  117. } /* set_selection */
  118.  
  119.  
  120. /* Pass the selection to STDWIN.
  121.    Always set cut buffer 0, also try primary selection.
  122.    Return success/failure of the latter. */
  123.  
  124. static int
  125. pass_selection(vt, data, len)
  126.     VT *vt;
  127.     char *data;
  128.     int len;
  129. {
  130.     wsetcutbuffer(0, data, len);
  131.     return wsetselection(vt->win, WS_PRIMARY, data, len);
  132. }
  133.  
  134.  
  135. /* Interface to STDWIN selection and cut buffer: save the copied text.
  136.    Returns success/failure */
  137.  
  138. static int
  139. extract_selection(vt, row1, col1, row2, col2)
  140.     VT *vt;
  141. {
  142.     /* Swap if needed to make sure (row1, col1) <= (row2, col2) */
  143.     if (row1 > row2 || row1 == row2 && col1 > col2) {
  144.     register int scratch;
  145.     scratch = row1; row1 = row2; row2 = scratch;
  146.     scratch = col1; col1 = col2; col2 = scratch;
  147.     }
  148.  
  149.     /* Make sure (0, 0) <= (row1, col1) and (row2, col2) <= (vt->rows, 0) */
  150.     if (row1 < 0) { row1 = 0; col1 = 0; }
  151.     if (row2 > vt->rows) { row2 = vt->rows; col2 = 0; }
  152.  
  153.     /* Now, if (row1, col1) >= (row2, col2), the selection is empty */
  154.     if (row1 > row2 || row1 == row2 && col1 >= col2) {
  155.     wresetselection(WS_PRIMARY); /* Clear any previous selection */
  156.     return 1;
  157.     }
  158.  
  159.     /* Check for simple case -- everything on one line */
  160.     if (row1 == row2 && col2 <= vt->llen[row2])
  161.     return pass_selection(vt, vt->data[row1] + col1, col2 - col1);
  162.  
  163.     /* Harder case: more lines, or one line + end-of-line */
  164.  
  165.     {
  166.     char *str, *p;
  167.     int ok;
  168.  
  169.     /* Get (more than) enough memory, fail if can't get it */
  170.     p = str = malloc((row2 - row1 + 1) * (vt->cols + 1));
  171.     if (p == NULL) return 0; /* Fail */
  172.  
  173.     /* Copy first line, add a newline */
  174.     if (col1 < vt->llen[row1]) {
  175.         strncpy(p, vt->data[row1] + col1, vt->llen[row1] - col1);
  176.         p += vt->llen[row1] - col1;
  177.     }
  178.     *p++ = '\n';
  179.  
  180.     /* Copy intermediate lines, adding newlines */
  181.     while (++row1 < row2) {
  182.         strncpy(p, vt->data[row1], vt->llen[row1]);
  183.         p += vt->llen[row1];
  184.         *p++ = '\n';
  185.     }
  186.  
  187.     /* Copy last line -- if this is not the first as well, nor too far */
  188.     if (row1 == row2 && row2 < vt->rows) {
  189.         if (col2 <= vt->llen[row2]) {
  190.         strncpy(p, vt->data[row2], col2);
  191.         p += col2;
  192.         }
  193.         else {
  194.         /* Beyond last char, copy a \n as well */
  195.         strncpy(p, vt->data[row2], vt->llen[row2]);
  196.         p += vt->llen[row2];
  197.         *p++ = '\n';
  198.         }
  199.     }
  200.  
  201.     /* Pass the string to STDWIN, free it, and return success */
  202.     ok = pass_selection(vt, str, (int) (p - str));
  203.     free(str);
  204.     return ok;
  205.     }
  206. }
  207.  
  208.  
  209. /* Symbolic values for the modes we can be in while selecting: */
  210.  
  211. #define SEL_CHARS    0    /* Selecting chars */
  212. #define SEL_WORDS    1    /* Selecting words */
  213. #define SEL_LINES    2    /* Selecting lines */
  214. #define SEL_KINDS    3    /* How many modes we know */
  215.  
  216. /* Macros to distinguish between various "brands" of characters.
  217.    A "word" is a sequence of characters of the same brand */
  218.  
  219. #define BRAND_LETTER    0
  220. #define BRAND_SPACE    1
  221. #define BRAND_PUNCT    2
  222.  
  223. /* Determine the brand of a character */
  224.  
  225. static int
  226. brand(ch)
  227.     int ch;
  228. {
  229.     return (('a' <= ch && ch <= 'z') ||
  230.      ('A' <= ch && ch <= 'Z') || ('0' <= ch && ch <= '9') ||
  231.      (ch == '_') ? BRAND_LETTER :
  232.      (ch == ' ' || ch == '\t') ? BRAND_SPACE : BRAND_PUNCT);
  233. }
  234.  
  235.  
  236. /* Called by the mainloop upon a mouse-down. Exits when the mouse is
  237.    up again; any other intermediate events terminates the selection.
  238.    Returns whether the selection succeeded */
  239.  
  240. int
  241. vtselect(vt, e)
  242.     VT *vt;
  243.     EVENT *e;
  244. {
  245.     int first_row, first_col; /* Coords save at mouse-down */
  246.     int was_lazy; /* Zapped because vtsetcursor is lazy as well */
  247.     int csr_row, csr_col; /* Cursor saved at mouse-down */
  248.     int button_down = 1; /* That's the reason we're called after all */
  249.     int sel_mode = SEL_CHARS; /* This one is not yet handled */
  250.     int timer_pending = 0;
  251.     int success = 1; /* We are optimists */
  252.  
  253.     /* Save cursor position */
  254.     was_lazy = vt->lazy; vt->lazy = 0;
  255.     csr_row = vt->cur_row;
  256.     csr_col = vt->cur_col;
  257.  
  258.     /* Init */
  259.     first_row = e->u.where.v / vt->cheight;
  260.     first_col = (e->u.where.h + vt->cwidth/2) / vt->cwidth;
  261.     if (first_col > vt->llen[first_row]) {
  262.     /* Clicked beyond eoln; use first char on next line instead */
  263.     ++first_row;
  264.     first_col = 0;
  265.     }
  266.  
  267.     vtsetcursor(vt, first_row, first_col);
  268.  
  269.     do {
  270.     int row, col; /* Current mouse position */
  271.  
  272.     wgetevent(e);
  273.     switch (e->type) {
  274.     case WE_MOUSE_UP:
  275.         button_down = 0;
  276.         wsettimer(vt->win, 2);
  277.         timer_pending = 1;
  278.         break;
  279.     case WE_MOUSE_MOVE:
  280.         break;
  281.     case WE_MOUSE_DOWN:
  282.         if (e->u.where.button != 1) {
  283.         /* E.g. paste-button; stop selection */
  284.         timer_pending = button_down = 0;
  285.         wungetevent(e);
  286.         break;
  287.         }
  288.         button_down = 1;
  289.         sel_mode = (sel_mode + 1) % SEL_KINDS;
  290.         break;
  291.     case WE_EXTERN:    /* Got output from child - save */
  292.         ++extra_downs;
  293.         continue;    /* Get next event */
  294.     case WE_TIMER:
  295.         timer_pending = 0;
  296.         break;
  297.     default:
  298.         wungetevent(e);
  299.         success = 0;
  300.         goto reset;
  301.     }
  302.  
  303.     /*
  304.      * We only get here when we want
  305.      * to draw the current selection;
  306.      * Compute new coords
  307.      */
  308.  
  309.     row = e->u.where.v / vt->cheight;
  310.     col = (e->u.where.h + vt->cwidth/2) / vt->cwidth;
  311.     vtsetcursor(vt, row, col);
  312.  
  313. #if 0    /* To do: Make sure everything in the neighbourhood can be seen: */
  314.     /* This does not work; it's far too fast */
  315.     if (vt->rows > 3 && vt->cols > 3)
  316.         wshow(vt->win,
  317.         e->u.where.h - vt->cwidth, e->u.where.v - vt->cheight,
  318.         e->u.where.h + vt->cwidth, e->u.where.v + vt->cheight);
  319. #endif
  320.  
  321.     switch (sel_mode) {
  322.     int rs, cs;
  323.     case SEL_CHARS:
  324.     case SEL_WORDS:
  325.         /* Clip row and col */
  326.         if (row > vt->rows) row = vt->rows;
  327.         else if (row < 0) row = 0;
  328.         if (col > vt->cols) col = vt->cols;
  329.         else if (col < 0) col = 0;
  330.         rs = first_row;
  331.         cs = first_col;
  332.         if (sel_mode == SEL_CHARS) {
  333.         /* Select including the eoln when beyond last char */
  334.         if (vt->llen[row] < col) col = vt->cols;
  335.         } else {
  336.         /* Sort coordinates */
  337.         if (rs > row || (rs == row && cs > col)) {
  338.             register tmp;
  339.             tmp = row; row = rs; rs = tmp;
  340.             tmp = col; col = cs; cs = tmp;
  341.         }
  342.         /* Expand */
  343.         while (cs > 0 &&
  344.             brand(vt->data[rs][cs]) == brand(vt->data[rs][cs - 1]))
  345.             --cs;
  346.         if (col >= vt->llen[row]) col = vt->cols;
  347.         else while (++col < vt->llen[row] &&
  348.             brand(vt->data[row][col - 1]) == brand(vt->data[row][col]))
  349.             ;
  350.         }
  351.         /* Update screen */
  352.         set_selection(vt, rs, cs, row, col);
  353.         break;
  354.     case SEL_LINES:
  355.         if (++row > vt->rows) row = vt->rows;
  356.         set_selection(vt,
  357.         first_row >= row ? first_row + 1 : first_row, 0, row, 0);
  358.         break;
  359.     }
  360.  
  361.     } while (button_down || timer_pending);
  362.  
  363.     /* Now pass the selection to STDWIN */
  364.     if (!extract_selection(vt,
  365.             vt->sel_row1, vt->sel_col1, vt->sel_row2, vt->sel_col2))
  366.         wfleep(); /* Give the user some indication that it failed */
  367.  
  368. reset:
  369.     /* Invert back to normal:    */
  370.     set_selection(vt, 0, 0, 0, 0);
  371.     vtsetcursor(vt, csr_row, csr_col);
  372.     vt->lazy = was_lazy;
  373.     return success;
  374. }
  375.  
  376.  
  377. /* Extend the selection */
  378.  
  379. int
  380. vtextendselection(vt, ep)
  381.     VT *vt;
  382.     EVENT *ep;
  383. {
  384.     /* XXX not yet implemented */
  385.     wfleep();
  386.     return 0;
  387. }
  388.