home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 1 / Atari Mega Archive - Volume 1.iso / gnu / progutil / stdwin.zoo / textedit / textedit.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-03-30  |  14.8 KB  |  795 lines

  1. /* Text Edit, high level routines */
  2. /* $Header: /userfs3/amoeba/guido/src/stdwin/textedit/RCS/textedit.c,v 1.3 89/07/24 13:48:58 guido Exp Locker: guido $ */
  3.  
  4. #include "text.h"
  5.  
  6. #ifdef __STDC__
  7. # define    P(s) s
  8. #else
  9. # define P(s) ()
  10. #endif
  11.  
  12.  
  13. /* textedit.c */
  14. static void teinschar P((TEXTEDIT *tp , int c ));
  15. static void tesetoptdata P((TEXTEDIT *tp ));
  16. static bool teoptinschar P((TEXTEDIT *tp , int c ));
  17. static void teinsert P((TEXTEDIT *tp , char *str , int len ));
  18. static void terecompute P((TEXTEDIT *tp , int first , int last ));
  19. static int tesetstart P((TEXTEDIT *tp , lineno i , bufpos pos , bufpos last ));
  20. static int teendofline P((TEXTEDIT *tp , bufpos pos ));
  21. static int tewordbegin P((TEXTEDIT *tp , int f ));
  22. static int tewordend P((TEXTEDIT *tp , int f ));
  23. static int _wdrawpar P((int left , int top , char *text , int width , bool draw ));
  24.  
  25. #undef P
  26.  
  27. void
  28. tereplace(tp, str)
  29.     TEXTEDIT *tp;
  30.     char *str;
  31. {
  32.     int len= (int)strlen(str);
  33.     
  34.     if (len == 1 && teoptinschar(tp, str[0]))
  35.         return;
  36.     
  37.     teinsert(tp, str, len);
  38. }
  39.  
  40. static void
  41. teinschar(tp, c)
  42.     TEXTEDIT *tp;
  43.     int c;
  44. {
  45.     char cbuf[2];
  46.     
  47.     if (teoptinschar(tp, c))
  48.         return;
  49.     
  50.     cbuf[0]= c;
  51.     cbuf[1]= EOS;
  52.     teinsert(tp, cbuf, 1);
  53. }
  54.  
  55. /* Optimization for the common case insert char.
  56.    Assumes text measurement is additive. */
  57.  
  58. static void
  59. tesetoptdata(tp)
  60.     TEXTEDIT *tp;
  61. {
  62.     lineno i;
  63.     bufpos k, pos, end;
  64.     
  65.     zcheck();
  66.     zassert(tp->foclen == 0);
  67.     
  68.     pos= zaddgap(tp->foc);
  69.     tp->opt_i= i= tewhichline(tp, pos, FALSE);
  70.     tp->opt_h= tp->left + tetextwidth(tp, tp->start[i], pos);
  71.     tp->opt_v= tp->top + i*tp->vspace;
  72.     end= tp->start[i+1];
  73.     if (end > pos && zcharbefore(end) == EOL)
  74.         zdecr(&end);
  75.     while (end > pos && zcharbefore(end) == ' ')
  76.         zdecr(&end);
  77.     for (k= pos; k < end; zincr(&k)) {
  78.         if (zcharat(k) == '\t')
  79.             break;
  80.     }
  81.     if (k < end) {
  82.         tp->opt_end=
  83.             tp->left + tetextwidth(tp, tp->start[i], znext(k));
  84.         tp->opt_avail= tp->opt_end -
  85.             (tp->left + tetextwidth(tp, tp->start[i], k));
  86.     }
  87.     else {
  88.         tp->opt_end= tp->right;
  89.         tp->opt_avail= tp->width - tetextwidth(tp, tp->start[i], end);
  90.     }
  91.     if (tp->start[i] > 0 && zcharbefore(tp->start[i]) != EOL) {
  92.         tp->opt_in_first_word= TRUE;
  93.         for (k= tp->start[i]; k < pos; zincr(&k)) {
  94.             if (isspace(zcharat(k))) {
  95.                 tp->opt_in_first_word= FALSE;
  96.                 break;
  97.             }
  98.         }
  99.     }
  100.     else
  101.         tp->opt_in_first_word= FALSE;
  102.     tp->opt_valid= TRUE;
  103. }
  104.  
  105. static bool
  106. teoptinschar(tp, c)
  107.     TEXTEDIT *tp;
  108.     int c;
  109. {
  110.     int w;
  111.     
  112.     if (tp->foclen != 0 || c == EOL || c == '\t' || tp->focprev)
  113.         return FALSE;
  114.     if (!tp->opt_valid)
  115.         tesetoptdata(tp);
  116.     if (c == ' ' && tp->opt_in_first_word)
  117.         return FALSE;
  118.     w= wcharwidth(c);
  119.     if (w >= tp->opt_avail)
  120.         return FALSE;
  121.     
  122.     temovegapto(tp, tp->foc);
  123.     if (tp->gaplen < 1)
  124.         tegrowgapby(tp, 1+RESERVE);
  125.     if (tp->start[tp->opt_i] == zgapend)
  126.         tp->start[tp->opt_i]= tp->gap;
  127.     ++tp->gap;
  128.     --tp->gaplen;
  129.     tp->buf[tp->foc]= c;
  130.     ++tp->foc;
  131.     
  132.     tp->opt_avail -= w;
  133.     wscroll(tp->win,
  134.         tp->opt_h, tp->opt_v,
  135.         tp->opt_end, tp->opt_v + tp->vspace,
  136.         w, 0);
  137.     wbegindrawing(tp->win);
  138.     wdrawchar(tp->opt_h, tp->opt_v, c);
  139.     wenddrawing(tp->win);
  140.     tp->opt_h += w;
  141.     wsetcaret(tp->win, tp->opt_h, tp->opt_v);
  142.     wshow(tp->win, tp->opt_h, tp->opt_v, tp->opt_h, tp->opt_v + tp->vspace);
  143.     tp->aim= tp->opt_h;
  144.     
  145.     return TRUE;
  146. }
  147.  
  148. static void
  149. teinsert(tp, str, len)
  150.     TEXTEDIT *tp;
  151.     char *str;
  152.     int len;
  153. {
  154.     focpos oldfoc= tp->foc;
  155.     
  156.     tehidefocus(tp);
  157.     temovegapto(tp, zfocend);
  158.     tp->gap= tp->foc;
  159.     tp->gaplen += tp->foclen;
  160.     teemptygap(tp);
  161.     tp->foclen= 0;
  162.     if (tp->gaplen < len)
  163.         tegrowgapby(tp, len-tp->gaplen+RESERVE);
  164.     strncpy(tp->buf+tp->gap, str, (size_t)len);
  165.     tp->gap += len;
  166.     tp->gaplen -= len;
  167.     tp->foc += len;
  168.     terecompute(tp, zaddgap(oldfoc), zaddgap(tp->foc));
  169. }
  170.  
  171. static int lasteol;    /* Optimization trick for teendofline */
  172.  
  173. static void
  174. terecompute(tp, first, last)
  175.     TEXTEDIT *tp;
  176.     int first, last;
  177. {
  178.     lineno i;
  179.     lineno chfirst, chlast; /* Area to pass to wchange */
  180.     lineno shift= 0; /* Lines to shift down (negative: up) */
  181.     vcoord newbottom;
  182.     
  183.     tp->start[0]= zaddgap(0);
  184.     
  185.     i= 2;
  186.     while (i <= tp->nlines && tp->start[i] < first)
  187.         ++i;
  188.     i -= 2;
  189.     chfirst= tp->nlines;
  190.     chlast= i;
  191.     lasteol= -1;
  192.     
  193.     /* TO DO: scroll up/down if inserting/deleting lines */
  194.     
  195.     for (;; ++i) {
  196.         bufpos end= teendofline(tp, tp->start[i]);
  197.         bool unchanged= (i < tp->nlines && end == tp->start[i+1]);
  198.         if (!unchanged)
  199.             shift += tesetstart(tp, i+1, end, last);
  200.         if (!(unchanged && end < first)) {
  201.             if (i < chfirst)
  202.                 chfirst= i;
  203.             chlast= i+1;
  204.         }
  205.         if (end >= tp->buflen) {
  206.             if (end > tp->start[i] && zcharbefore(end) == EOL)
  207.                 continue;
  208.             else
  209.                 break;
  210.         }
  211.         if (unchanged && end > last) {
  212.             i= tp->nlines-1;
  213.             break;
  214.         }
  215.     }
  216.     
  217.     zassert(tp->nlines > i);
  218.     
  219.     if (tp->drawing) {
  220.         if (shift != 0) {
  221.             lineno k= chlast;
  222.             if (shift > 0)
  223.                 k -= shift;
  224.             wscroll(tp->win,
  225.                 tp->left, tp->top + k*tp->vspace,
  226.                 tp->right, tp->top + tp->nlines*tp->vspace,
  227.                 0, shift*tp->vspace);
  228.         }
  229.         
  230.         wchange(tp->win,
  231.             tp->left, tp->top + chfirst*tp->vspace,
  232.             tp->right, tp->top + chlast*tp->vspace);
  233.     }
  234.     
  235.     tp->nlines= i+1;
  236.     newbottom= tp->top + tp->vspace*tp->nlines;
  237.     if (newbottom < tp->bottom)
  238.         wchange(tp->win,
  239.             tp->left, newbottom, tp->right, tp->bottom);
  240.     tp->bottom= newbottom;
  241.     tp->aim= UNDEF;
  242.     tp->focprev= FALSE;
  243.     if (tp->drawing)
  244.         tesetcaret(tp);
  245.     
  246.     zcheck();
  247. }
  248.  
  249. static int
  250. tesetstart(tp, i, pos, last)
  251.     register TEXTEDIT *tp;
  252.     register lineno i;
  253.     bufpos pos, last;
  254. {
  255.     if (i > tp->nlines) {
  256.         tp->nlines= i;
  257.         if (tp->nlines >= tp->nstart) {
  258.             tp->nstart= tp->nlines + STARTINCR;
  259.             tp->start= (bufpos*)zrealloc((char*)tp->start,
  260.                 (int)(tp->nstart*(int)sizeof(int)));
  261.         }
  262.         tp->start[i]= pos;
  263.         return 0;
  264.     }
  265.     else {
  266.         lineno shift= 0;
  267.         lineno k;
  268.         for (k= i; k < tp->nlines; ++k) {
  269.             if (tp->start[k] > pos)
  270.                 break;
  271.         }
  272.         shift= k-1 - i;
  273.         /* start[k] should really be start[i+1] */
  274.         if (shift < 0 && tp->start[k] >= last) { /* Insert one */
  275.             ++tp->nlines;
  276.             if (tp->nlines >= tp->nstart) {
  277.                 tp->nstart= tp->nlines + STARTINCR;
  278.                 tp->start= (int*)zrealloc((char*)tp->start,
  279.                     (int)(tp->nstart*(int)sizeof(int)));
  280.             }
  281.             for (k= tp->nlines; k > i; --k)
  282.                 tp->start[k]= tp->start[k-1];
  283.         }
  284.         else if (shift > 0 && pos >= last) { /* Delete some */
  285.             for (; k <= tp->nlines; ++k)
  286.                 tp->start[k-shift]= tp->start[k];
  287.             tp->nlines -= shift;
  288.             if (tp->nlines < tp->nstart - STARTINCR) {
  289.                 tp->nstart= tp->nlines+1;
  290.                 tp->start= (int*)zrealloc((char*)tp->start,
  291.                     (int)(tp->nstart*(int)sizeof(int)));
  292.             }
  293.         }
  294.         else
  295.             shift= 0; /* Don't shift (yet) */
  296.         tp->start[i]= pos;
  297.         return -shift;
  298.     }
  299. }
  300.  
  301. static int
  302. teendofline(tp, pos)
  303.     TEXTEDIT *tp;
  304.     bufpos pos;
  305. {
  306.     bufpos end= tp->buflen;
  307.     bufpos k;
  308.     
  309.     /* Find first EOL if any */
  310.     if (lasteol >= pos)
  311.         k= lasteol;
  312.     else {
  313.         for (k= pos; k < end && zcharat(k) != EOL; zincr(&k))
  314.             ;
  315.         lasteol= k;
  316.     }
  317.     
  318.     end= tetextbreak(tp, pos, k, tp->width);
  319.     
  320.     /* Extend with any spaces immediately following end */
  321.     for (; end < tp->buflen && zcharat(end) == ' '; zincr(&end))
  322.         ;
  323.     
  324.     if (end < tp->buflen) {
  325.         /* Extend with immediately following EOL */
  326.         if (zcharat(end) == EOL)
  327.             zincr(&end);
  328.         else {
  329.             /* Search back for space before last word */
  330.             for (k= end; zdecr(&k) >= pos && !isspace(zcharat(k)); )
  331.                 ;
  332.             
  333.             if (k >= pos)
  334.                 end= znext(k);
  335.         }
  336.     }
  337.  
  338.     /* Each line must be at least one character long,
  339.        otherwise a very narrow text-edit box would cause
  340.        the size calculation to last forever */
  341.     if (end == pos && end < tp->buflen)
  342.         zincr(&end);
  343.     
  344.     return end;
  345. }
  346.  
  347. bool
  348. teevent(tp, e)
  349.     TEXTEDIT *tp;
  350.     EVENT *e;
  351. {
  352.     if (e->window != tp->win)
  353.         return FALSE;
  354.     
  355.     switch (e->type) {
  356.     
  357.     case WE_CHAR:
  358.         teinschar(tp, e->u.character);
  359.         break;
  360.     
  361.     case WE_COMMAND:
  362.         switch (e->u.command) {
  363.         case WC_BACKSPACE:
  364.             tebackspace(tp);
  365.             break;
  366.         case WC_RETURN:
  367.             teinschar(tp, EOL);
  368.             break;
  369.         case WC_TAB:
  370.             teinschar(tp, '\t');
  371.             break;
  372.         case WC_LEFT:
  373.         case WC_RIGHT:
  374.         case WC_UP:
  375.         case WC_DOWN:
  376.             tearrow(tp, e->u.command);
  377.             break;
  378.         default:
  379.             return FALSE;
  380.         }
  381.         break;
  382.     
  383.     case WE_MOUSE_DOWN:
  384.         {
  385.             int h= e->u.where.h, v= e->u.where.v;
  386.             if (h >= tp->left && h <= tp->right &&
  387.                     v >= tp->top && v <= tp->bottom)
  388.                 teclicknew(tp, h, v,
  389.                     e->u.where.button == 2,
  390.                     e->u.where.clicks > 1);
  391.             else
  392.                 return FALSE;
  393.         }
  394.         break;
  395.     
  396.     case WE_MOUSE_MOVE:
  397.     case WE_MOUSE_UP:
  398.         if (!tp->mdown)
  399.             return FALSE;
  400.         teclicknew(tp, e->u.where.h, e->u.where.v, TRUE, tp->dclick);
  401.         if (e->type == WE_MOUSE_UP)
  402.             tp->mdown= FALSE;
  403.         break;
  404.     
  405.     default:
  406.         return FALSE;
  407.     
  408.     }
  409.     
  410.     /* If broke out of switch: */
  411.     return TRUE;
  412. }
  413.  
  414. void
  415. tearrow(tp, code)
  416.     TEXTEDIT *tp;
  417.     int code;
  418. {
  419.     lineno i;
  420.     bufpos pos;
  421.     
  422.     tehidefocus(tp);
  423.     
  424.     switch (code) {
  425.     
  426.     case WC_LEFT:
  427.         if (tp->foclen != 0)
  428.             tp->foclen= 0;
  429.         else {
  430.             if (tp->foc > 0)
  431.                 --tp->foc;
  432.             else
  433.                 wfleep();
  434.         }
  435.         tp->aim= UNDEF;
  436.         tp->focprev= FALSE;
  437.         break;
  438.     
  439.     case WC_RIGHT:
  440.         if (tp->foclen != 0) {
  441.             tp->foc += tp->foclen;
  442.             tp->foclen= 0;
  443.         }
  444.         else {
  445.             if (tp->foc < tp->buflen-tp->gaplen)
  446.                 ++tp->foc;
  447.             else
  448.                 wfleep();
  449.         }
  450.         tp->aim= UNDEF;
  451.         tp->focprev= FALSE;
  452.         break;
  453.     
  454.     /* TO DO: merge the following two cases */
  455.     
  456.     case WC_UP:
  457.         if (tp->foclen > 0)
  458.             tp->foclen= 0;
  459.         else {
  460.             pos= zaddgap(tp->foc);
  461.             i= tewhichline(tp, pos, tp->focprev);
  462.             if (i <= 0)
  463.                 wfleep();
  464.             else {
  465.                 if (tp->aim == UNDEF)
  466.                     tp->aim= tp->left + tetextwidth(tp,
  467.                         tp->start[i], pos);
  468.                 --i;
  469.                 pos= tetextround(tp, i, tp->aim);
  470.                 tp->foc= zsubgap(pos);
  471.                 tp->focprev= (pos == tp->start[i+1]);
  472.             }
  473.         }
  474.         break;
  475.     
  476.     case WC_DOWN:
  477.         if (tp->foclen > 0) {
  478.             tp->foc += tp->foclen;
  479.             tp->foclen= 0;
  480.         }
  481.         else {
  482.             pos= zaddgap(tp->foc);
  483.             i= tewhichline(tp, pos, tp->focprev);
  484.             if (i+1 >= tp->nlines)
  485.                 wfleep();
  486.             else {
  487.                 if (tp->aim == UNDEF)
  488.                     tp->aim= tp->left + tetextwidth(tp,
  489.                         tp->start[i], pos);
  490.                 ++i;
  491.                 pos= tetextround(tp, i, tp->aim);
  492.                 tp->foc= zsubgap(pos);
  493.                 tp->focprev= (pos == tp->start[i+1]);
  494.             }
  495.         }
  496.         break;
  497.     
  498.     default:
  499.         dprintf("tearrow: bad code %d", code);
  500.         break;
  501.         
  502.     }
  503.     tesetcaret(tp);
  504. }
  505.  
  506. void
  507. tebackspace(tp)
  508.     TEXTEDIT *tp;
  509. {
  510.     if (tp->foclen == 0) {
  511.         if (tp->foc == 0) {
  512.             wfleep();
  513.             return;
  514.         }
  515.         --tp->foc;
  516.         tp->foclen= 1;
  517.     }
  518.     teinsert(tp, "", 0);
  519. }
  520.  
  521. bool
  522. teclicknew(tp, h, v, extend, dclick)
  523.     TEXTEDIT *tp;
  524.     coord h, v;
  525.     bool extend, dclick;
  526. {
  527.     lineno i;
  528.     bufpos pos;
  529.     focpos f;
  530.     
  531.     tp->dclick= dclick;
  532.     pos= tewhereis(tp, h, v, &i);
  533.     f= zsubgap(pos);
  534.     if (extend) {
  535.         if (!tp->mdown) {
  536.             tp->mdown= TRUE;
  537.             if (f - tp->foc < tp->foc + tp->foclen - f)
  538.                 tp->anchor= tp->foc + tp->foclen;
  539.             else
  540.                 tp->anchor= tp->foc;
  541.             tp->anchor2= tp->anchor;
  542.         }
  543.         if (f >= tp->anchor) {
  544.             if (dclick)
  545.                 f= tewordend(tp, f);
  546.             techangefocus(tp, tp->anchor, f);
  547.         }
  548.         else {
  549.             if (dclick)
  550.                 f= tewordbegin(tp, f);
  551.             techangefocus(tp, f, tp->anchor2);
  552.         }
  553.     }
  554.     else {
  555.         tp->mdown= TRUE;
  556.         tp->anchor= tp->anchor2= f;
  557.         if (dclick) {
  558.             tp->anchor= tewordbegin(tp, tp->anchor);
  559.             tp->anchor2= tewordend(tp, f);
  560.         }
  561.         techangefocus(tp, tp->anchor, tp->anchor2);
  562.     }
  563.     tp->aim= UNDEF;
  564.     tp->focprev= (tp->foclen == 0 && pos == tp->start[i+1]);
  565.     tesetcaret(tp);
  566.     return TRUE;
  567. }
  568.  
  569. /* Return f, 'rounded down' to a word begin */
  570.  
  571. static int
  572. tewordbegin(tp, f)
  573.     TEXTEDIT *tp;
  574.     int f;
  575. {
  576.     f= zaddgap(f);
  577.     for (;;) {
  578.         if (f == 0 || isspace(zcharbefore(f)))
  579.             break;
  580.         zdecr(&f);
  581.     }
  582.     return zsubgap(f);
  583. }
  584.  
  585. /* Ditto to word end */
  586.  
  587. static int
  588. tewordend(tp, f)
  589.     TEXTEDIT *tp;
  590.     int f;
  591. {
  592.     f= zaddgap(f);
  593.     for (;;) {
  594.         if (f >= tp->buflen || isspace(zcharat(f)))
  595.             break;
  596.         zincr(&f);
  597.     }
  598.     return zsubgap(f);
  599. }
  600.  
  601. int
  602. tegetleft(tp)
  603.     TEXTEDIT *tp;
  604. {
  605.     return tp->left;
  606. }
  607.  
  608. int
  609. tegettop(tp)
  610.     TEXTEDIT *tp;
  611. {
  612.     return tp->top;
  613. }
  614.  
  615. int
  616. tegetright(tp)
  617.     TEXTEDIT *tp;
  618. {
  619.     return tp->right;
  620. }
  621.  
  622. int
  623. tegetbottom(tp)
  624.     TEXTEDIT *tp;
  625. {
  626.     return tp->bottom;
  627. }
  628.  
  629. void
  630. temove(tp, left, top, width)
  631.     TEXTEDIT *tp;
  632.     coord left, top, width;
  633. {
  634.     temovenew(tp, left, top, left+width, top + tp->nlines*tp->vspace);
  635. }
  636.  
  637. void
  638. temovenew(tp, left, top, right, bottom)
  639.     TEXTEDIT *tp;
  640.     int left, top, right, bottom;
  641. {
  642.     int oldheight= tp->bottom - tp->top;
  643.     tp->left= left;
  644.     tp->top= top;
  645.     tp->right= right;
  646.     tp->bottom= tp->top + oldheight;
  647.     if (right - left != tp->width) {
  648.         tp->width= right - left;
  649.         tp->nlines= 0; /* Experimental! */
  650.         terecompute(tp, 0, tp->buflen);
  651.     }
  652. }
  653.  
  654. void
  655. tesetfocus(tp, foc1, foc2)
  656.     TEXTEDIT *tp;
  657.     focpos foc1, foc2;
  658. {
  659.     if (foc1 > tp->buflen - tp->gaplen)
  660.         foc1= tp->buflen - tp->gaplen;
  661.     if (foc2 > tp->buflen - tp->gaplen)
  662.         foc2= tp->buflen - tp->gaplen;
  663.     if (foc1 < 0)
  664.         foc1= 0;
  665.     if (foc2 < foc1)
  666.         foc2= foc1;
  667.     techangefocus(tp, foc1, foc2);
  668.     tp->aim= UNDEF;
  669.     tp->focprev= FALSE;
  670.     tesetcaret(tp);
  671. }
  672.  
  673. int
  674. tegetfoc1(tp)
  675.     TEXTEDIT *tp;
  676. {
  677.     return tp->foc;
  678. }
  679.  
  680. int
  681. tegetfoc2(tp)
  682.     TEXTEDIT *tp;
  683. {
  684.     return tp->foc + tp->foclen;
  685. }
  686.  
  687. int
  688. tegetnlines(tp)
  689.     TEXTEDIT *tp;
  690. {
  691.     return tp->nlines;
  692. }
  693.  
  694. char *
  695. tegettext(tp)
  696.     TEXTEDIT *tp;
  697. {
  698.     temovegapto(tp, tp->buflen - tp->gaplen);
  699.     if (tp->gaplen < 1)
  700.         tegrowgapby(tp, 1+RESERVE);
  701.     tp->buf[tp->gap]= EOS;
  702.     return tp->buf;
  703. }
  704.  
  705. int
  706. tegetlen(tp)
  707.     TEXTEDIT *tp;
  708. {
  709.     return tp->buflen - tp->gaplen;
  710. }
  711.  
  712. void
  713. tesetbuf(tp, buf, buflen)
  714.     TEXTEDIT *tp;
  715.     char *buf;
  716.     int buflen;
  717. {
  718.     bool drawing= tp->drawing;
  719.     
  720.     if (buf == NULL || buflen < 0)
  721.         return;
  722.     if (drawing)
  723.         wchange(tp->win, tp->left, tp->top, tp->right, tp->bottom);
  724.     free(tp->buf);
  725.     tp->buf= buf;
  726.     tp->buflen= buflen;
  727.     tp->foc= tp->foclen= tp->gap= tp->gaplen= 0;
  728.     tp->drawing= FALSE;
  729.     terecompute(tp, 0, tp->buflen);
  730.     if (drawing) {
  731.         tp->drawing= TRUE;
  732.         wchange(tp->win, tp->left, tp->top, tp->right, tp->bottom);
  733.     }
  734. }
  735.  
  736.  
  737. /* The following paragraph-drawing routines are experimental.
  738.    They cannibalize on the existing text-edit code,
  739.    which makes it trivial to ensure the lay-out is the same,
  740.    but causes overhead to initialize a text-edit struct.
  741.    The flag 'drawing' has been added to the textedit struct,
  742.    which suppresses calls to tesetcaret, wchange and wscroll
  743.    from tesetup and terecompute.
  744.    It doesn't suppress actual drawing, which only occurs when
  745.    tedraw is called.
  746.    Note -- this could be optimized, but it is infrequently,
  747.    so I don't care until I get complaints. */
  748.  
  749. /* Draw a paragraph of text, exactly like tedraw would draw it.
  750.    Parameters are the top left corner, the width, the text and its length.
  751.    Return value is the v coordinate of the bottom line.
  752.    An empty string is drawn as one blank line. */
  753.  
  754. int
  755. wdrawpar(left, top, text, width)
  756.     int left, top;
  757.     char *text;
  758.     int width;
  759. {
  760.     return _wdrawpar(left, top, text, width, TRUE);
  761. }
  762.  
  763. /* Measure the height of a paragraph of text, when drawn with wdrawpar. */
  764.  
  765. int
  766. wparheight(text, width)
  767.     char *text;
  768.     int width;
  769. {
  770.     return _wdrawpar(0, 0, text, width, FALSE);
  771. }
  772.  
  773. /* Routine to do the dirty work for the above two.
  774.    Size calculations are implemented by going through the normal
  775.    routine but suppressing the actual drawing. */
  776.  
  777. static int
  778. _wdrawpar(left, top, text, width, draw)
  779.     int left, top;
  780.     char *text;
  781.     int width;
  782.     bool draw;
  783. {
  784.     TEXTEDIT *tp= tesetup((WINDOW*)NULL, left, top, left+width, top, FALSE);
  785.     int v;
  786.     
  787.     tesetbuf(tp, text, (int)strlen(text));
  788.     if (draw)
  789.         tedraw(tp);
  790.     v= tegetbottom(tp);
  791.     tp->buf= NULL;
  792.     tefree(tp);
  793.     return v;
  794. }
  795.