home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / magazine / drdobbs / 1991 / 06 / dflat3 / textbox.c < prev    next >
Text File  |  1991-05-19  |  13KB  |  540 lines

  1. /* ------------- textbox.c ------------ */
  2.  
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <string.h>
  6. #include <dos.h>
  7. #include "dflat.h"
  8.  
  9. static char *GetTextLine(WINDOW wnd, int selection);
  10.  
  11. #ifdef INCLUDE_SCROLLBARS
  12. static int HScrolling = FALSE;
  13. static int VScrolling = FALSE;
  14. #endif
  15.  
  16. int TextBoxProc(WINDOW wnd, MESSAGE msg, PARAM p1, PARAM p2)
  17. {
  18. #ifdef INCLUDE_SCROLLBARS
  19.     int    mx = (int) p1 - GetLeft(wnd);
  20.     int    my = (int) p2 - GetTop(wnd);
  21. #endif
  22.     switch (msg)    {
  23.         case CREATE_WINDOW:
  24.             wnd->wlines = wnd->wtop = wnd->wleft =
  25.                 wnd->textlen = wnd->textwidth = 0;
  26.             wnd->text = NULL;
  27.             wnd->HScrollBox = wnd->VScrollBox = 1;
  28.             ClearTextPointers(wnd);
  29.             ClearBlock(wnd);
  30.             break;
  31.         case ADDTEXT:    {
  32.             /* ======== need to assure that length !> 64K ======= */
  33.             int adln = strlen((char *)p1);
  34.             if (wnd->text != NULL)    {
  35.                 int txln = strlen(wnd->text);
  36.                 if (txln+adln > wnd->textlen)    {
  37.                     wnd->text = realloc(wnd->text, txln+adln+2);
  38.                     wnd->textlen = txln+adln;
  39.                 }
  40.             }
  41.             else    {
  42.                 wnd->text = malloc(adln+2);
  43.                 *wnd->text = '\0';
  44.                 wnd->textlen = adln+1;
  45.             }
  46.             strcat(wnd->text, (char*) p1);
  47.             strcat(wnd->text, "\n");
  48.             wnd->wlines++;
  49.             wnd->textwidth = max(wnd->textwidth, adln);
  50.             BuildTextPointers(wnd);
  51.             break;
  52.         }
  53.         case SETTEXT:    {
  54.             char *cp, *cp1;
  55.             int len;
  56.             cp = cp1 = (void *) p1;
  57.             len = strlen(cp)+1;
  58.             if (wnd->text == NULL || wnd->textlen < len)    {
  59.                 wnd->textlen = len;
  60.                 if (wnd->text)
  61.                     free(wnd->text);
  62.                 if ((wnd->text = realloc(wnd->text, strlen(cp)+1)) == NULL)
  63.                     break;
  64.             }
  65.             wnd->wlines = wnd->textwidth = 0;
  66.             strcpy(wnd->text, cp);
  67.             while ((cp = strchr(cp, '\n')) != NULL)    {
  68.                 wnd->wlines++;
  69.                 cp++;
  70.                 wnd->textwidth = max(wnd->textwidth, (int)(cp-cp1));
  71.                 cp1 = cp;
  72.             }
  73.             BuildTextPointers(wnd);
  74.             break;
  75.         }
  76.         case CLEARTEXT:
  77.             if (wnd->text != NULL)
  78.                 free(wnd->text);
  79.             wnd->text = NULL;
  80.             wnd->textlen = 0;
  81.             wnd->wlines = 0;
  82.             wnd->textwidth = 0;
  83.             wnd->wtop = wnd->wleft = 0;
  84.             ClearBlock(wnd);
  85.             ClearTextPointers(wnd);
  86.             break;
  87.         case SETFOCUS:
  88.             if (!p1 && isMultiLine(wnd))
  89.                 if (BlockMarked(wnd))    {
  90.                     ClearBlock(wnd);
  91.                     if (isVisible(wnd) && wnd == inFocus)
  92.                         SendMessage(wnd, PAINT, 0, 0);
  93.                 }
  94.             break;
  95.         case KEYBOARD:
  96. #ifdef INCLUDE_SYSTEM_MENUS
  97.             if (WindowMoving || WindowSizing)
  98.                 break;
  99. #endif
  100.             switch ((int) p1)    {
  101.                 case UP:
  102.                     if (wnd->wtop)
  103.                         SendMessage(wnd, SCROLL, FALSE, 0);
  104.                     return TRUE;
  105.                 case DN:
  106.                     if (wnd->wtop+ClientHeight(wnd) < wnd->wlines)
  107.                         SendMessage(wnd, SCROLL, TRUE, 0);
  108.                     return TRUE;
  109.                 case FWD:
  110.                     SendMessage(wnd, HORIZSCROLL, TRUE, 0);
  111.                     return TRUE;
  112.                 case BS:
  113.                     SendMessage(wnd, HORIZSCROLL, FALSE, 0);
  114.                     return TRUE;
  115.                 case PGUP:
  116.                     if (wnd->wtop)    {
  117.                         wnd->wtop -= ClientHeight(wnd);
  118.                         if (wnd->wtop < 0)
  119.                             wnd->wtop = 0;
  120.                         SendMessage(wnd, PAINT, 0, 0);
  121.                         return TRUE;
  122.                     }
  123.                     return TRUE;
  124.                 case PGDN:
  125.                     if (wnd->wtop+ClientHeight(wnd) < wnd->wlines)    {
  126.                         wnd->wtop += ClientHeight(wnd);
  127.                         if (wnd->wtop > wnd->wlines-ClientHeight(wnd))
  128.                             wnd->wtop = wnd->wlines-ClientHeight(wnd);
  129.                         SendMessage(wnd, PAINT, 0, 0);
  130.                         return TRUE;
  131.                     }
  132.                     return TRUE;
  133.                 case HOME:
  134.                     if (wnd->wtop || wnd->wleft)    {
  135.                         wnd->wtop = wnd->wleft = 0;
  136.                         SendMessage(wnd, PAINT, 0, 0);
  137.                     }
  138.                     return TRUE;
  139.                 case END:
  140.                     if (wnd->wtop+ClientHeight(wnd) < wnd->wlines)    {
  141.                         wnd->wtop = wnd->wlines-ClientHeight(wnd);
  142.                         wnd->wleft = 0;
  143.                         SendMessage(wnd, PAINT, 0, 0);
  144.                     }
  145.                     return TRUE;
  146.                 default:
  147.                     break;
  148.             }
  149.             break;
  150.         case LEFT_BUTTON:
  151. #ifdef INCLUDE_SYSTEM_MENUS
  152.             if (WindowSizing || WindowMoving)
  153.                 return FALSE;
  154. #endif
  155. #ifdef INCLUDE_SCROLLBARS
  156.             if (TestAttribute(wnd, VSCROLLBAR) && (VScrolling ||
  157.                     mx == WindowWidth(wnd)-1))    {
  158.  
  159.                 /* -------- in the right border ------- */
  160.                 if (my == 0 || my == ClientHeight(wnd)+1)
  161.                     /* ------ above or below the scroll bar ---- */
  162.                     break;
  163.  
  164.                 /* ---------- in the scroll bar ----------- */
  165.  
  166.                 VScrolling = TRUE;
  167.  
  168.                 if (my == 1)    {
  169.                     /* -------- top scroll button --------- */
  170.                     SendMessage(wnd, SCROLL, FALSE, 0);
  171.                     return TRUE;
  172.                 }
  173.                 if (my == ClientHeight(wnd))    {
  174.                     /* -------- bottom scroll button --------- */
  175.                     SendMessage(wnd, SCROLL, TRUE, 0);
  176.                     return TRUE;
  177.                 }
  178.                 if (my-1 != wnd->VScrollBox)    {
  179.                     int dir = my-1 > wnd->VScrollBox;
  180.  
  181.                     while (dir ? (my-1 > wnd->VScrollBox) :
  182.                                  (my-1 < wnd->VScrollBox))    {
  183.                         if (!SendMessage(NULLWND, TESTMOUSE, 0, 0))
  184.                             break;
  185.                         SendMessage(wnd, SCROLL, dir, 0);
  186.                     }
  187.                     return TRUE;
  188.                 }
  189.             }
  190.             if (TestAttribute(wnd, HSCROLLBAR) &&
  191.                 (HScrolling || my == WindowHeight(wnd)-1))    {
  192.                 /* -------- in the bottom border ------- */
  193.                 if (mx == 0 || my == ClientWidth(wnd)+1)
  194.                     /* ------  outside the scroll bar ---- */
  195.                     break;
  196.  
  197.                 HScrolling = TRUE;
  198.  
  199.                 if (mx == 1)    {
  200.                     SendMessage(wnd, HORIZSCROLL, FALSE, 0);
  201.                     return TRUE;
  202.                 }
  203.                 if (mx == WindowWidth(wnd)-2)    {
  204.                     SendMessage(wnd, HORIZSCROLL, TRUE, 0);
  205.                     return TRUE;
  206.                 }
  207.                 if (mx-1 != wnd->HScrollBox)    {
  208.                     int dir = mx-1 > wnd->HScrollBox;
  209.                     while (dir ? (mx-1 > wnd->HScrollBox) :
  210.                                  (mx-1 < wnd->HScrollBox))    {
  211.                         if (!SendMessage(NULLWND, TESTMOUSE, 0, 0))
  212.                             break;
  213.                         SendMessage(wnd, HORIZSCROLL, dir, 0);
  214.                     }
  215.                     return TRUE;
  216.                 }
  217.             }
  218.             break;
  219.         case BUTTON_RELEASED:
  220.             HScrolling = VScrolling = FALSE;
  221.             break;
  222. #endif
  223.         case SCROLL:
  224.             if (isVisible(wnd))    {
  225.                 if (p1 == 0)    {
  226.                     if (wnd->wtop == 0)
  227.                         return FALSE;
  228.                 }
  229.                 else if (wnd->wtop+ClientHeight(wnd) >= wnd->wlines)
  230.                     return FALSE;
  231.                 if (p1)
  232.                     wnd->wtop++;
  233.                 else
  234.                     --wnd->wtop;
  235.                 SendMessage(wnd, PAINT, 0, 0);
  236.                 return TRUE;
  237.             }
  238.             break;
  239.         case HORIZSCROLL:
  240.             if (p1 == 0 && wnd->wleft == 0)
  241.                 return FALSE;
  242.             if (p1)    {
  243.                 if (wnd->wleft + ClientWidth(wnd)-1 >= wnd->textwidth)
  244.                     return FALSE;
  245.                 wnd->wleft++;
  246.             }
  247.             else
  248.                 --wnd->wleft;
  249.             SendMessage(wnd, PAINT, 0, 0);
  250.             return TRUE;
  251.         case PAINT:
  252.             if (isVisible(wnd) && wnd->wlines)    {
  253.                 RECT rc, rcc;
  254.                 int y;
  255.                 char blankline[SCREENWIDTH+1];
  256.  
  257.                 if ((RECT *)p1 == NULL)
  258.                     rc = RelativeWindowRect(wnd, WindowRect(wnd));
  259.                 else
  260.                     rc = *(RECT *)p1;
  261.  
  262.                 if (TestAttribute(wnd, HASBORDER) &&
  263.                         RectRight(rc) >= WindowWidth(wnd)-1)    {
  264.                     if (RectLeft(rc) >= WindowWidth(wnd)-1)
  265.                         return TRUE;
  266.                     RectRight(rc) = WindowWidth(wnd)-2;
  267.                 }
  268.  
  269.                 rcc = AdjustRectangle(wnd, rc);
  270.                 memset(blankline, ' ', SCREENWIDTH);
  271.                 blankline[RectRight(rcc)+1] = '\0';
  272.  
  273.                 for (y = RectTop(rc); y <= RectBottom(rc); y++)    {
  274.                     int yy;
  275.                     if (TestAttribute(wnd, HASBORDER | TITLEBAR))    {
  276.                         if (y < TopBorderAdj(wnd))
  277.                             continue;
  278.                         if (y > WindowHeight(wnd)-2)
  279.                             continue;
  280.                     }
  281.                     yy = y-TopBorderAdj(wnd);
  282.                     if (yy < wnd->wlines-wnd->wtop)
  283.                         WriteTextLine(wnd, &rc, yy+wnd->wtop, FALSE);
  284.                     else    {
  285.                         SetStandardColor(wnd);
  286.                         writeline(wnd, blankline+RectLeft(rcc),
  287.                                 RectLeft(rcc)+1, y, FALSE);
  288.                     }
  289.                 }
  290. #ifdef INCLUDE_SCROLLBARS
  291.                 if (TestAttribute(wnd, VSCROLLBAR))    {
  292.                     int pagelen = wnd->wlines - ClientHeight(wnd);
  293.                     int barlen = ClientHeight(wnd)-2;
  294.                     int lines_tick;
  295.  
  296.                     if (pagelen < 1 || barlen < 1)
  297.                         wnd->VScrollBox = 1;
  298.                     else    {
  299.                         if (pagelen > barlen)
  300.                             lines_tick = pagelen / barlen;
  301.                         else
  302.                             lines_tick = barlen / pagelen;
  303.                         wnd->VScrollBox = 1 + (wnd->wtop / lines_tick);
  304.                         if (wnd->VScrollBox > ClientHeight(wnd)-2 ||
  305.                                 wnd->wtop + ClientHeight(wnd) >= wnd->wlines)
  306.                             wnd->VScrollBox = ClientHeight(wnd)-2;
  307.                     }
  308.                     SendMessage(wnd, BORDER, p1, 0);
  309.                 }
  310.                 if (TestAttribute(wnd, HSCROLLBAR))    {
  311.                     int pagewidth = wnd->textwidth - ClientWidth(wnd);
  312.                     int barlen = ClientWidth(wnd)-2;
  313.                     int chars_tick;
  314.  
  315.                     if (pagewidth < 1 || barlen < 1)
  316.                         wnd->HScrollBox = 1;
  317.                     else     {
  318.                         if (pagewidth > barlen)
  319.                             chars_tick = pagewidth / barlen;
  320.                         else
  321.                             chars_tick = barlen / pagewidth;
  322.                         wnd->HScrollBox = 1 + (wnd->wleft / chars_tick);
  323.                         if (wnd->HScrollBox > ClientWidth(wnd)-2 ||
  324.                                 wnd->wleft + ClientWidth(wnd) >= wnd->textwidth)
  325.                             wnd->HScrollBox = ClientWidth(wnd)-2;
  326.                     }
  327.                     SendMessage(wnd, BORDER, p1, 0);
  328.                 }
  329. #endif
  330.                 return FALSE;
  331.             }
  332.             break;
  333.         case CLOSE_WINDOW:
  334.             SendMessage(wnd, CLEARTEXT, 0, 0);
  335.             if (wnd->extension != NULL)    {
  336.                 free(wnd->extension);
  337.                 wnd->extension = NULL;
  338.             }
  339.             break;
  340.         default:
  341.             break;
  342.     }
  343.     return BaseWndProc(TEXTBOX, wnd, msg, p1, p2);
  344. }
  345.  
  346. static char *GetTextLine(WINDOW wnd, int selection)
  347. {
  348.     char *line;
  349.     int len = 0;
  350.     char *cp, *cp1;
  351.     cp = cp1 = TextLine(wnd, selection);
  352.     while (*cp && *cp != '\n')    {
  353.         len++;
  354.         cp++;
  355.     }
  356.     line = malloc(len+6);
  357.     if (line != NULL)    {
  358.         memmove(line, cp1, len);
  359.         line[len] = '\0';
  360.     }
  361.     return line;
  362. }
  363.  
  364. void WriteTextLine(WINDOW wnd, RECT *rcc, int y, int reverse)
  365. {
  366.     int len = 0;
  367.     int dif = 0;
  368.     static char line[100];
  369.     RECT rc;
  370.     char *lp, *svlp;
  371.     int lnlen;
  372.     int i;
  373.     int trunc = FALSE;
  374.  
  375.     if (y < wnd->wtop || y >= wnd->wtop+ClientHeight(wnd))
  376.         return;
  377.  
  378.     if (rcc == NULL)
  379.         rc = RelativeWindowRect(wnd, WindowRect(wnd));
  380.     else
  381.         rc = *rcc;
  382.  
  383.     if (RectLeft(rc) >= WindowWidth(wnd)-1)
  384.         return;
  385.     if (RectRight(rc) == 0)
  386.         return;
  387.  
  388.     rc = AdjustRectangle(wnd, rc);
  389.  
  390.     lp = svlp = GetTextLine(wnd, y);
  391.     lnlen = LineLength(lp);
  392.  
  393.     /* -------- insert block color change controls ------- */
  394.     if (BlockMarked(wnd))    {
  395.         int bbl = wnd->BlkBegLine;
  396.         int bel = wnd->BlkEndLine;
  397.         int bbc = wnd->BlkBegCol;
  398.         int bec = wnd->BlkEndCol;
  399.         int by = y;
  400.  
  401.         if (bbl > bel)    {
  402.             swap(bbl, bel);
  403.             swap(bbc, bec);
  404.         }
  405.         if (bbl == bel && bbc > bec)
  406.             swap(bbc, bec);
  407.  
  408.         if (by >= bbl && by <= bel)    {
  409.             /* ------ the block includes this line ----- */
  410.             int blkbeg = 0;
  411.             int blkend = lnlen;
  412.             if (!(by > bbl && by < bel))    {
  413.                 /* --- the entire line is not in the block --- */
  414.                 if (by == bbl)
  415.                     /* ---- the block begins on this line ---- */
  416.                     blkbeg = bbc;
  417.                 if (by == bel)
  418.                     /* ---- the block ends on this line ---- */
  419.                     blkend = bec;
  420.             }
  421.             memmove(lp+blkend+1, lp+blkend, strlen(lp+blkend)+1);
  422.             lp[blkend] = RESETCOLOR;
  423.             memmove(lp+blkbeg+3, lp+blkbeg, strlen(lp+blkbeg)+1);
  424.             lp[blkbeg] = CHANGECOLOR;
  425.             SetReverseColor(wnd);
  426.             lp[blkbeg+1] = foreground | 0x80;
  427.             lp[blkbeg+2] = background | 0x80;
  428.             lnlen += 4;
  429.         }
  430.     }
  431.  
  432.     for (i = 0; i < wnd->wleft+3; i++)    {
  433.         if (*(lp+i) == '\0')
  434.             break;
  435.         if (*(unsigned char *)(lp + i) == RESETCOLOR)
  436.             break;
  437.     }
  438.     if (*(lp+i) && i < wnd->wleft+3)    {
  439.         if (wnd->wleft+4 > lnlen)
  440.             trunc = TRUE;
  441.         else 
  442.             lp += 4;
  443.     }
  444.     else     {
  445.         for (i = 0; i < wnd->wleft; i++)    {
  446.             if (*(lp+i) == '\0')
  447.                 break;
  448.             if (*(unsigned char *)(lp + i) == CHANGECOLOR)    {
  449.                 *(lp+wnd->wleft+2) = *(lp+i+2);
  450.                 *(lp+wnd->wleft+1) = *(lp+i+1);
  451.                 *(lp+wnd->wleft) = *(lp+i);
  452.                 break;
  453.             }
  454.         }
  455.     }
  456.  
  457.     if (!trunc)    {
  458.         if (lnlen < wnd->wleft)
  459.             lnlen = 0;
  460.         else
  461.             lp += wnd->wleft;
  462.  
  463.  
  464.         if (y-wnd->wtop < RectTop(rc) || y-wnd->wtop > RectBottom(rc))
  465.             return;
  466.  
  467.         if (lnlen > RectLeft(rc))    {
  468.             lp += RectLeft(rc);
  469.             lnlen = LineLength(lp);
  470.             len = min(lnlen, RectWidth(rc));
  471.             lnlen = LineLength(lp);
  472.             dif = strlen(lp) - lnlen;
  473.             len += dif;
  474.             if (len > 0)
  475.                 strncpy(line, lp, len);
  476.         }
  477.     }
  478.  
  479.     while (len < RectWidth(rc)+dif)
  480.         line[len++] = ' ';
  481.     line[len] = '\0';
  482.  
  483.     dif = 0;
  484.     if (reverse)    {
  485.         char *cp = line;
  486.         SetReverseColor(wnd);
  487.         while ((cp = strchr(cp, CHANGECOLOR)) != NULL)    {
  488.             cp += 2;
  489.             *cp++ = background | 0x80;
  490.         }
  491.         if (*(unsigned char *)line == CHANGECOLOR)
  492.             dif = 3;
  493.     }
  494.     else
  495.         SetStandardColor(wnd);
  496.     writeline(wnd, line+dif,
  497.                 RectLeft(rc)+BorderAdj(wnd),
  498.                     y-wnd->wtop+TopBorderAdj(wnd), FALSE);
  499.     if (svlp != NULL)
  500.         free(svlp);
  501. }
  502.  
  503. void SetAnchor(WINDOW wnd, int mx, int my)
  504. {
  505.     if (BlockMarked(wnd))    {
  506.         ClearBlock(wnd);
  507.         SendMessage(wnd, PAINT, 0, 0);
  508.     }
  509.     /* ------ set the anchor ------ */
  510.     wnd->BlkBegLine = wnd->BlkEndLine = my;
  511.     wnd->BlkBegCol = wnd->BlkEndCol = mx;
  512.     WriteTextLine(wnd, NULL, my, FALSE);
  513. }
  514.  
  515. void ClearTextPointers(WINDOW wnd)
  516. {
  517.     wnd->extension = realloc(wnd->extension, sizeof(int));
  518.     if (wnd->extension != NULL)
  519.         *(int *)(wnd->extension) = 0;
  520. }
  521.  
  522. void BuildTextPointers(WINDOW wnd)
  523. {
  524.     if (wnd->wlines)    {
  525.         char *cp = wnd->text;
  526.         int *cp1 = realloc(wnd->extension, wnd->wlines * sizeof(int));
  527.         if (cp1 != NULL)    {
  528.             int i;
  529.             wnd->extension = cp1;
  530.             for (i = 0; i < wnd->wlines; i++)    {
  531.                 *(cp1 + i) = (int) (cp - (char *) wnd->text);
  532.                 if ((cp = strchr(cp, '\n')) == NULL)
  533.                     break;
  534.                 cp++;
  535.             }
  536.         }
  537.     }
  538. }
  539.  
  540.