home *** CD-ROM | disk | FTP | other *** search
/ DP Tool Club 24 / CD_ASCQ_24_0995.iso / vrac / dflt20.zip / TEXTBOX.C < prev    next >
C/C++ Source or Header  |  1994-12-26  |  28KB  |  886 lines

  1. /* ------------- textbox.c ------------ */
  2.  
  3. #include "dflat.h"
  4.  
  5. static void ComputeWindowTop(WINDOW);
  6. static void ComputeWindowLeft(WINDOW);
  7. static int ComputeVScrollBox(WINDOW);
  8. static int ComputeHScrollBox(WINDOW);
  9. static void MoveScrollBox(WINDOW, int);
  10. static char *GetTextLine(WINDOW, int);
  11.  
  12. BOOL VSliding;
  13. BOOL HSliding;
  14.  
  15. /* ------------ ADDTEXT Message -------------- */
  16. static BOOL AddTextMsg(WINDOW wnd, char *txt)
  17. {
  18.     /* --- append text to the textbox's buffer --- */
  19.     unsigned adln = strlen(txt);
  20.     if (adln > (unsigned)0xfff0)
  21.         return FALSE;
  22.     if (wnd->text != NULL)    {
  23.         /* ---- appending to existing text ---- */
  24.         unsigned txln = strlen(wnd->text);
  25.         if ((long)txln+adln > (unsigned) 0xfff0)
  26.             return FALSE;
  27.         if (txln+adln > wnd->textlen)    {
  28.             wnd->text = DFrealloc(wnd->text, txln+adln+3);
  29.             wnd->textlen = txln+adln+1;
  30.         }
  31.     }
  32.     else    {
  33.         /* ------ 1st text appended ------ */
  34.         wnd->text = DFcalloc(1, adln+3);
  35.         wnd->textlen = adln+1;
  36.     }
  37.     wnd->TextChanged = TRUE;
  38.     if (wnd->text != NULL)    {
  39.         /* ---- append the text ---- */
  40.         strcat(wnd->text, txt);
  41.         strcat(wnd->text, "\n");
  42.         BuildTextPointers(wnd);
  43.         return TRUE;
  44.     }
  45.     return FALSE;
  46. }
  47.  
  48. /* ------------ DELETETEXT Message -------------- */
  49. static void DeleteTextMsg(WINDOW wnd, int lno)
  50. {
  51.     char *cp1 = TextLine(wnd, lno);
  52.     --wnd->wlines;
  53.     if (lno == wnd->wlines)
  54.         *cp1 = '\0';
  55.     else     {
  56.         char *cp2 = TextLine(wnd, lno+1);
  57.         memmove(cp1, cp2, strlen(cp2)+1);
  58.     }
  59.     BuildTextPointers(wnd);
  60. }
  61.  
  62. /* ------------ INSERTTEXT Message -------------- */
  63. static void InsertTextMsg(WINDOW wnd, char *txt, int lno)
  64. {
  65.     if (AddTextMsg(wnd, txt))    {
  66.         int len = strlen(txt)+1;
  67.         char *cp2 = TextLine(wnd, lno);
  68.         char *cp1 = cp2+len;
  69.         memmove(cp1, cp2, strlen(cp2)-len);
  70.         strcpy(cp2, txt);
  71.         *(cp2+len-1) = '\n';
  72.         BuildTextPointers(wnd);
  73.         wnd->TextChanged = TRUE;
  74.     }
  75. }
  76.  
  77. /* ------------ SETTEXT Message -------------- */
  78. static void SetTextMsg(WINDOW wnd, char *txt)
  79. {
  80.     /* -- assign new text value to textbox buffer -- */
  81.     unsigned int len = strlen(txt)+1;
  82.     SendMessage(wnd, CLEARTEXT, 0, 0);
  83.     wnd->textlen = len;
  84.     wnd->text=DFrealloc(wnd->text, len+1);
  85.     wnd->text[len] = '\0';
  86.     strcpy(wnd->text, txt);
  87.     BuildTextPointers(wnd);
  88. }
  89.  
  90. /* ------------ CLEARTEXT Message -------------- */
  91. static void ClearTextMsg(WINDOW wnd)
  92. {
  93.     /* ----- clear text from textbox ----- */
  94.     if (wnd->text != NULL)
  95.         free(wnd->text);
  96.     wnd->text = NULL;
  97.     wnd->textlen = 0;
  98.     wnd->wlines = 0;
  99.     wnd->textwidth = 0;
  100.     wnd->wtop = wnd->wleft = 0;
  101.     ClearTextBlock(wnd);
  102.     ClearTextPointers(wnd);
  103. }
  104.  
  105. /* ------------ KEYBOARD Message -------------- */
  106. static int KeyboardMsg(WINDOW wnd, PARAM p1)
  107. {
  108.     switch ((int) p1)    {
  109.         case UP:
  110.             return SendMessage(wnd,SCROLL,FALSE,0);
  111.         case DN:
  112.             return SendMessage(wnd,SCROLL,TRUE,0);
  113.         case FWD:
  114.             return SendMessage(wnd,HORIZSCROLL,TRUE,0);
  115.         case BS:
  116.             return SendMessage(wnd,HORIZSCROLL,FALSE,0);
  117.         case PGUP:
  118.             return SendMessage(wnd,SCROLLPAGE,FALSE,0);
  119.         case PGDN:
  120.             return SendMessage(wnd,SCROLLPAGE,TRUE,0);
  121.         case CTRL_PGUP:
  122.             return SendMessage(wnd,HORIZPAGE,FALSE,0);
  123.         case CTRL_PGDN:
  124.             return SendMessage(wnd,HORIZPAGE,TRUE,0);
  125.         case HOME:
  126.             return SendMessage(wnd,SCROLLDOC,TRUE,0);
  127.         case END:
  128.             return SendMessage(wnd,SCROLLDOC,FALSE,0);
  129.         default:
  130.             break;
  131.     }
  132.     return FALSE;
  133. }
  134.  
  135. /* ------------ LEFT_BUTTON Message -------------- */
  136. static int LeftButtonMsg(WINDOW wnd, PARAM p1, PARAM p2)
  137. {
  138.     int mx = (int) p1 - GetLeft(wnd);
  139.     int my = (int) p2 - GetTop(wnd);
  140.     if (TestAttribute(wnd, VSCROLLBAR) &&
  141.                         mx == WindowWidth(wnd)-1)    {
  142.         /* -------- in the right border ------- */
  143.         if (my == 0 || my == ClientHeight(wnd)+1)
  144.             /* --- above or below the scroll bar --- */
  145.             return FALSE;
  146.         if (my == 1)
  147.             /* -------- top scroll button --------- */
  148.             return SendMessage(wnd, SCROLL, FALSE, 0);
  149.         if (my == ClientHeight(wnd))
  150.             /* -------- bottom scroll button --------- */
  151.             return SendMessage(wnd, SCROLL, TRUE, 0);
  152.         /* ---------- in the scroll bar ----------- */
  153.         if (!VSliding && my-1 == wnd->VScrollBox)    {
  154.             RECT rc;
  155.             VSliding = TRUE;
  156.             rc.lf = rc.rt = GetRight(wnd);
  157.             rc.tp = GetTop(wnd)+2;
  158.             rc.bt = GetBottom(wnd)-2;
  159.             return SendMessage(NULL, MOUSE_TRAVEL,
  160.                 (PARAM) &rc, 0);
  161.         }
  162.         if (my-1 < wnd->VScrollBox)
  163.             return SendMessage(wnd,SCROLLPAGE,FALSE,0);
  164.         if (my-1 > wnd->VScrollBox)
  165.             return SendMessage(wnd,SCROLLPAGE,TRUE,0);
  166.     }
  167.     if (TestAttribute(wnd, HSCROLLBAR) &&
  168.                         my == WindowHeight(wnd)-1) {
  169.         /* -------- in the bottom border ------- */
  170.         if (mx == 0 || my == ClientWidth(wnd)+1)
  171.             /* ------  outside the scroll bar ---- */
  172.             return FALSE;
  173.         if (mx == 1)
  174.             return SendMessage(wnd, HORIZSCROLL,FALSE,0);
  175.         if (mx == WindowWidth(wnd)-2)
  176.             return SendMessage(wnd, HORIZSCROLL,TRUE,0);
  177.         if (!HSliding && mx-1 == wnd->HScrollBox)    {
  178.             /* --- hit the scroll box --- */
  179.             RECT rc;
  180.             rc.lf = GetLeft(wnd)+2;
  181.             rc.rt = GetRight(wnd)-2;
  182.             rc.tp = rc.bt = GetBottom(wnd);
  183.             /* - keep the mouse in the scroll bar - */
  184.             SendMessage(NULL,MOUSE_TRAVEL,(PARAM)&rc,0);
  185.             HSliding = TRUE;
  186.             return TRUE;
  187.         }
  188.         if (mx-1 < wnd->HScrollBox)
  189.             return SendMessage(wnd,HORIZPAGE,FALSE,0);
  190.         if (mx-1 > wnd->HScrollBox)
  191.             return SendMessage(wnd,HORIZPAGE,TRUE,0);
  192.     }
  193.     return FALSE;
  194. }
  195.  
  196. /* ------------ MOUSE_MOVED Message -------------- */
  197. static BOOL MouseMovedMsg(WINDOW wnd, PARAM p1, PARAM p2)
  198. {
  199.     int mx = (int) p1 - GetLeft(wnd);
  200.     int my = (int) p2 - GetTop(wnd);
  201.     if (VSliding)    {
  202.         /* ---- dragging the vertical scroll box --- */
  203.         if (my-1 != wnd->VScrollBox)    {
  204.             foreground = FrameForeground(wnd);
  205.             background = FrameBackground(wnd);
  206.             wputch(wnd, SCROLLBARCHAR, WindowWidth(wnd)-1,
  207.                     wnd->VScrollBox+1);
  208.             wnd->VScrollBox = my-1;
  209.             wputch(wnd, SCROLLBOXCHAR, WindowWidth(wnd)-1,
  210.                     my);
  211.         }
  212.         return TRUE;
  213.     }
  214.     if (HSliding)    {
  215.         /* --- dragging the horizontal scroll box --- */
  216.         if (mx-1 != wnd->HScrollBox)    {
  217.             foreground = FrameForeground(wnd);
  218.             background = FrameBackground(wnd);
  219.             wputch(wnd, SCROLLBARCHAR, wnd->HScrollBox+1,
  220.                     WindowHeight(wnd)-1);
  221.             wnd->HScrollBox = mx-1;
  222.             wputch(wnd, SCROLLBOXCHAR, mx, WindowHeight(wnd)-1);
  223.         }
  224.         return TRUE;
  225.     }
  226.     return FALSE;
  227. }
  228.  
  229. /* ------------ BUTTON_RELEASED Message -------------- */
  230. static void ButtonReleasedMsg(WINDOW wnd)
  231. {
  232.     if (HSliding || VSliding)    {
  233.         /* release the mouse ouside the scroll bar */
  234.         SendMessage(NULL, MOUSE_TRAVEL, 0, 0);
  235.         VSliding ? ComputeWindowTop(wnd):ComputeWindowLeft(wnd);
  236.         SendMessage(wnd, PAINT, 0, 0);
  237.         SendMessage(wnd, KEYBOARD_CURSOR, 0, 0);
  238.         VSliding = HSliding = FALSE;
  239.     }
  240. }
  241.  
  242. /* ------------ SCROLL Message -------------- */
  243. static BOOL ScrollMsg(WINDOW wnd, PARAM p1)
  244. {
  245.     /* ---- vertical scroll one line ---- */
  246.     if (p1)    {
  247.         /* ----- scroll one line up ----- */
  248.         if (wnd->wtop+ClientHeight(wnd) >= wnd->wlines)
  249.             return FALSE;
  250.         wnd->wtop++;
  251.     }
  252.     else    {
  253.         /* ----- scroll one line down ----- */
  254.         if (wnd->wtop == 0)
  255.             return FALSE;
  256.         --wnd->wtop;
  257.     }
  258.     if (isVisible(wnd))    {
  259.         RECT rc;
  260.         rc = ClipRectangle(wnd, ClientRect(wnd));
  261.         if (ValidRect(rc))    {
  262.             /* ---- scroll the window ----- */
  263.             if (wnd != inFocus)
  264.                 SendMessage(wnd, PAINT, 0, 0);
  265.             else    {
  266.                 scroll_window(wnd, rc, (int)p1);
  267.                 if (!(int)p1)
  268.                     /* -- write top line (down) -- */
  269.                     WriteTextLine(wnd,NULL,wnd->wtop,FALSE);
  270.                 else    {
  271.                     /* -- write bottom line (up) -- */
  272.                     int y=RectBottom(rc)-GetClientTop(wnd);
  273.                     WriteTextLine(wnd, NULL,
  274.                         wnd->wtop+y, FALSE);
  275.                 }
  276.             }
  277.         }
  278.         /* ---- reset the scroll box ---- */
  279.         if (TestAttribute(wnd, VSCROLLBAR))    {
  280.             int vscrollbox = ComputeVScrollBox(wnd);
  281.             if (vscrollbox != wnd->VScrollBox)
  282.                 MoveScrollBox(wnd, vscrollbox);
  283.         }
  284.     }
  285.     return TRUE;
  286. }
  287.  
  288. /* ------------ HORIZSCROLL Message -------------- */
  289. static BOOL HorizScrollMsg(WINDOW wnd, PARAM p1)
  290. {
  291.     /* --- horizontal scroll one column --- */
  292.     if (p1)    {
  293.         /* --- scroll left --- */
  294.         if (wnd->wleft + ClientWidth(wnd)-1 >= wnd->textwidth)
  295.             return FALSE;
  296.         wnd->wleft++;
  297.     }
  298.     else    {
  299.         /* --- scroll right --- */
  300.         if (wnd->wleft == 0)
  301.             return FALSE;
  302.         --wnd->wleft;
  303.     }
  304.     SendMessage(wnd, PAINT, 0, 0);
  305.     return TRUE;
  306. }
  307.  
  308. /* ------------  SCROLLPAGE Message -------------- */
  309. static void ScrollPageMsg(WINDOW wnd, PARAM p1)
  310. {
  311.     /* --- vertical scroll one page --- */
  312.     if ((int) p1 == FALSE)    {
  313.         /* ---- page up ---- */
  314.         if (wnd->wtop)
  315.             wnd->wtop -= ClientHeight(wnd);
  316.     }
  317.     else     {
  318.         /* ---- page down ---- */
  319.         if (wnd->wtop+ClientHeight(wnd) < wnd->wlines) {
  320.             wnd->wtop += ClientHeight(wnd);
  321.             if (wnd->wtop>wnd->wlines-ClientHeight(wnd))
  322.                 wnd->wtop=wnd->wlines-ClientHeight(wnd);
  323.         }
  324.     }
  325.     if (wnd->wtop < 0)
  326.         wnd->wtop = 0;
  327.     SendMessage(wnd, PAINT, 0, 0);
  328. }
  329.  
  330. /* ------------ HORIZSCROLLPAGE Message -------------- */
  331. static void HorizScrollPageMsg(WINDOW wnd, PARAM p1)
  332. {
  333.     /* --- horizontal scroll one page --- */
  334.     if ((int) p1 == FALSE)
  335.         /* ---- page left ----- */
  336.         wnd->wleft -= ClientWidth(wnd);
  337.     else    {
  338.         /* ---- page right ----- */
  339.         wnd->wleft += ClientWidth(wnd);
  340.         if (wnd->wleft > wnd->textwidth-ClientWidth(wnd))
  341.             wnd->wleft = wnd->textwidth-ClientWidth(wnd);
  342.     }
  343.     if (wnd->wleft < 0)
  344.         wnd->wleft = 0;
  345.     SendMessage(wnd, PAINT, 0, 0);
  346. }
  347.  
  348. /* ------------ SCROLLDOC Message -------------- */
  349. static void ScrollDocMsg(WINDOW wnd, PARAM p1)
  350. {
  351.     /* --- scroll to beginning or end of document --- */
  352.     if ((int) p1)
  353.         wnd->wtop = wnd->wleft = 0;
  354.     else if (wnd->wtop+ClientHeight(wnd) < wnd->wlines){
  355.         wnd->wtop = wnd->wlines-ClientHeight(wnd);
  356.         wnd->wleft = 0;
  357.     }
  358.     SendMessage(wnd, PAINT, 0, 0);
  359. }
  360.  
  361. /* ------------ PAINT Message -------------- */
  362. static void PaintMsg(WINDOW wnd, PARAM p1, PARAM p2)
  363. {
  364.     /* ------ paint the client area ----- */
  365.     RECT rc, rcc;
  366.     int y;
  367.     char blankline[201];
  368.  
  369.     /* ----- build the rectangle to paint ----- */
  370.     if ((RECT *)p1 == NULL)
  371.         rc=RelativeWindowRect(wnd, WindowRect(wnd));
  372.     else
  373.         rc= *(RECT *)p1;
  374.     if (TestAttribute(wnd, HASBORDER) &&
  375.             RectRight(rc) >= WindowWidth(wnd)-1) {
  376.         if (RectLeft(rc) >= WindowWidth(wnd)-1)
  377.             return;
  378.         RectRight(rc) = WindowWidth(wnd)-2;
  379.     }
  380.     rcc = AdjustRectangle(wnd, rc);
  381.  
  382.     if (!p2 && wnd != inFocus)
  383.         ClipString++;
  384.  
  385.     /* ----- blank line for padding ----- */
  386.     memset(blankline, ' ', SCREENWIDTH);
  387.     blankline[RectRight(rcc)+1] = '\0';
  388.  
  389.     /* ------- each line within rectangle ------ */
  390.     for (y = RectTop(rc); y <= RectBottom(rc); y++){
  391.         int yy;
  392.         /* ---- test outside of Client area ---- */
  393.         if (TestAttribute(wnd,
  394.                     HASBORDER | HASTITLEBAR))    {
  395.             if (y < TopBorderAdj(wnd))
  396.                 continue;
  397.             if (y > WindowHeight(wnd)-2)
  398.                 continue;
  399.         }
  400.         yy = y-TopBorderAdj(wnd);
  401.         if (yy < wnd->wlines-wnd->wtop)
  402.             /* ---- paint a text line ---- */
  403.             WriteTextLine(wnd, &rc,
  404.                         yy+wnd->wtop, FALSE);
  405.         else    {
  406.             /* ---- paint a blank line ---- */
  407.             SetStandardColor(wnd);
  408.             writeline(wnd, blankline+RectLeft(rcc),
  409.                     RectLeft(rcc)+BorderAdj(wnd), y, FALSE);
  410.         }
  411.     }
  412.     /* ------- position the scroll box ------- */
  413.     if (TestAttribute(wnd, VSCROLLBAR|HSCROLLBAR)) {
  414.         int hscrollbox = ComputeHScrollBox(wnd);
  415.         int vscrollbox = ComputeVScrollBox(wnd);
  416.         if (hscrollbox != wnd->HScrollBox ||
  417.                 vscrollbox != wnd->VScrollBox)    {
  418.             wnd->HScrollBox = hscrollbox;
  419.             wnd->VScrollBox = vscrollbox;
  420.             SendMessage(wnd, BORDER, p1, 0);
  421.         }
  422.     }
  423.     if (!p2 && wnd != inFocus)
  424.         --ClipString;
  425. }
  426.  
  427. /* ------------ CLOSE_WINDOW Message -------------- */
  428. static void CloseWindowMsg(WINDOW wnd)
  429. {
  430.     SendMessage(wnd, CLEARTEXT, 0, 0);
  431.     if (wnd->TextPointers != NULL)    {
  432.         free(wnd->TextPointers);
  433.         wnd->TextPointers = NULL;
  434.     }
  435. }
  436.  
  437. /* ----------- TEXTBOX Message-processing Module ----------- */
  438. int TextBoxProc(WINDOW wnd, MESSAGE msg, PARAM p1, PARAM p2)
  439. {
  440.     switch (msg)    {
  441.         case CREATE_WINDOW:
  442.             wnd->HScrollBox = wnd->VScrollBox = 1;
  443.             ClearTextPointers(wnd);
  444.             break;
  445.         case ADDTEXT:
  446.             return AddTextMsg(wnd, (char *) p1);
  447.         case DELETETEXT:
  448.             DeleteTextMsg(wnd, (int) p1);
  449.             return TRUE;
  450.         case INSERTTEXT:
  451.             InsertTextMsg(wnd, (char *) p1, (int) p2);
  452.             return TRUE;
  453.         case SETTEXT:
  454.             SetTextMsg(wnd, (char *) p1);
  455.             return TRUE;
  456.         case CLEARTEXT:
  457.             ClearTextMsg(wnd);
  458.             break;
  459.         case KEYBOARD:
  460.             if (WindowMoving || WindowSizing)
  461.                 break;
  462.             if (KeyboardMsg(wnd, p1))
  463.                 return TRUE;
  464.             break;
  465.         case LEFT_BUTTON:
  466.             if (WindowSizing || WindowMoving)
  467.                 return FALSE;
  468.             if (LeftButtonMsg(wnd, p1, p2))
  469.                 return TRUE;
  470.             break;
  471.         case MOUSE_MOVED:
  472.             if (MouseMovedMsg(wnd, p1, p2))
  473.                 return TRUE;
  474.             break;
  475.         case BUTTON_RELEASED:
  476.             ButtonReleasedMsg(wnd);
  477.             break;
  478.         case SCROLL:
  479.             return ScrollMsg(wnd, p1);
  480.         case HORIZSCROLL:
  481.             return HorizScrollMsg(wnd, p1);
  482.         case SCROLLPAGE:
  483.             ScrollPageMsg(wnd, p1);
  484.             return TRUE;
  485.         case HORIZPAGE:
  486.             HorizScrollPageMsg(wnd, p1);
  487.             return TRUE;
  488.         case SCROLLDOC:
  489.             ScrollDocMsg(wnd, p1);
  490.             return TRUE;
  491.         case PAINT:
  492.             if (isVisible(wnd))    {
  493.                 PaintMsg(wnd, p1, p2);
  494.                 return FALSE;
  495.             }
  496.             break;
  497.         case CLOSE_WINDOW:
  498.             CloseWindowMsg(wnd);
  499.             break;
  500.         default:
  501.             break;
  502.     }
  503.     return BaseWndProc(TEXTBOX, wnd, msg, p1, p2);
  504. }
  505.  
  506. /* ------ compute the vertical scroll box position from
  507.                    the text pointers --------- */
  508. static int ComputeVScrollBox(WINDOW wnd)
  509. {
  510.     int pagelen = wnd->wlines - ClientHeight(wnd);
  511.     int barlen = ClientHeight(wnd)-2;
  512.     int lines_tick;
  513.     int vscrollbox;
  514.  
  515.     if (pagelen < 1 || barlen < 1)
  516.         vscrollbox = 1;
  517.     else    {
  518.         if (pagelen > barlen)
  519.             lines_tick = pagelen / barlen;
  520.         else
  521.             lines_tick = barlen / pagelen;
  522.         vscrollbox = 1 + (wnd->wtop / lines_tick);
  523.         if (vscrollbox > ClientHeight(wnd)-2 ||
  524.                 wnd->wtop + ClientHeight(wnd) >= wnd->wlines)
  525.             vscrollbox = ClientHeight(wnd)-2;
  526.     }
  527.     return vscrollbox;
  528. }
  529.  
  530. /* ---- compute top text line from scroll box position ---- */
  531. static void ComputeWindowTop(WINDOW wnd)
  532. {
  533.     int pagelen = wnd->wlines - ClientHeight(wnd);
  534.     if (wnd->VScrollBox == 0)
  535.         wnd->wtop = 0;
  536.     else if (wnd->VScrollBox == ClientHeight(wnd)-2)
  537.         wnd->wtop = pagelen;
  538.     else    {
  539.         int barlen = ClientHeight(wnd)-2;
  540.         int lines_tick;
  541.  
  542.         if (pagelen > barlen)
  543.             lines_tick = barlen ? (pagelen / barlen) : 0;
  544.         else
  545.             lines_tick = pagelen ? (barlen / pagelen) : 0;
  546.         wnd->wtop = (wnd->VScrollBox-1) * lines_tick;
  547.         if (wnd->wtop + ClientHeight(wnd) > wnd->wlines)
  548.             wnd->wtop = pagelen;
  549.     }
  550.     if (wnd->wtop < 0)
  551.         wnd->wtop = 0;
  552. }
  553.  
  554. /* ------ compute the horizontal scroll box position from
  555.                    the text pointers --------- */
  556. static int ComputeHScrollBox(WINDOW wnd)
  557. {
  558.     int pagewidth = wnd->textwidth - ClientWidth(wnd);
  559.     int barlen = ClientWidth(wnd)-2;
  560.     int chars_tick;
  561.     int hscrollbox;
  562.  
  563.     if (pagewidth < 1 || barlen < 1)
  564.         hscrollbox = 1;
  565.     else     {
  566.         if (pagewidth > barlen)
  567.             chars_tick = barlen ? (pagewidth / barlen) : 0;
  568.         else
  569.             chars_tick = pagewidth ? (barlen / pagewidth) : 0;
  570.         hscrollbox = 1 + (chars_tick ? (wnd->wleft / chars_tick) : 0);
  571.         if (hscrollbox > ClientWidth(wnd)-2 ||
  572.                 wnd->wleft + ClientWidth(wnd) >= wnd->textwidth)
  573.             hscrollbox = ClientWidth(wnd)-2;
  574.     }
  575.     return hscrollbox;
  576. }
  577.  
  578. /* ---- compute left column from scroll box position ---- */
  579. static void ComputeWindowLeft(WINDOW wnd)
  580. {
  581.     int pagewidth = wnd->textwidth - ClientWidth(wnd);
  582.  
  583.     if (wnd->HScrollBox == 0)
  584.         wnd->wleft = 0;
  585.     else if (wnd->HScrollBox == ClientWidth(wnd)-2)
  586.         wnd->wleft = pagewidth;
  587.     else    {
  588.         int barlen = ClientWidth(wnd)-2;
  589.         int chars_tick;
  590.  
  591.         if (pagewidth > barlen)
  592.             chars_tick = pagewidth / barlen;
  593.         else
  594.             chars_tick = barlen / pagewidth;
  595.         wnd->wleft = (wnd->HScrollBox-1) * chars_tick;
  596.         if (wnd->wleft + ClientWidth(wnd) > wnd->textwidth)
  597.             wnd->wleft = pagewidth;
  598.     }
  599.     if (wnd->wleft < 0)
  600.         wnd->wleft = 0;
  601. }
  602.  
  603. /* ----- get the text to a specified line ----- */
  604. static char *GetTextLine(WINDOW wnd, int selection)
  605. {
  606.     char *line;
  607.     int len = 0;
  608.     char *cp, *cp1;
  609.     cp = cp1 = TextLine(wnd, selection);
  610.     while (*cp && *cp != '\n')    {
  611.         len++;
  612.         cp++;
  613.     }
  614.     line = DFmalloc(len+7);
  615.     memmove(line, cp1, len);
  616.     line[len] = '\0';
  617.     return line;
  618. }
  619.  
  620. /* ------- write a line of text to a textbox window ------- */
  621. void WriteTextLine(WINDOW wnd, RECT *rcc, int y, BOOL reverse)
  622. {
  623.     int len = 0;
  624.     int dif = 0;
  625.     unsigned char line[200];
  626.     RECT rc;
  627.     unsigned char *lp, *svlp;
  628.     int lnlen;
  629.     int i;
  630.     BOOL trunc = FALSE;
  631.  
  632.     /* ------ make sure y is inside the window ----- */
  633.     if (y < wnd->wtop || y >= wnd->wtop+ClientHeight(wnd))
  634.         return;
  635.  
  636.     /* ---- build the retangle within which can write ---- */
  637.     if (rcc == NULL)    {
  638.         rc = RelativeWindowRect(wnd, WindowRect(wnd));
  639.         if (TestAttribute(wnd, HASBORDER) &&
  640.                 RectRight(rc) >= WindowWidth(wnd)-1)
  641.             RectRight(rc) = WindowWidth(wnd)-2;
  642.     }
  643.     else
  644.         rc = *rcc;
  645.  
  646.     /* ----- make sure rectangle is within window ------ */
  647.     if (RectLeft(rc) >= WindowWidth(wnd)-1)
  648.         return;
  649.     if (RectRight(rc) == 0)
  650.         return;
  651.     rc = AdjustRectangle(wnd, rc);
  652.     if (y-wnd->wtop<RectTop(rc) || y-wnd->wtop>RectBottom(rc))
  653.         return;
  654.  
  655.     /* --- get the text and length of the text line --- */
  656.     lp = svlp = GetTextLine(wnd, y);
  657.     if (svlp == NULL)
  658.         return;
  659.     lnlen = LineLength(lp);
  660.  
  661.     if (wnd->protect)    {
  662.         char *pp = lp;
  663.         while (*pp)    {
  664.             if (isprint(*pp))
  665.                 *pp = '*';
  666.             pp++;
  667.         }
  668.     }
  669.  
  670.     /* -------- insert block color change controls ------- */
  671.     if (TextBlockMarked(wnd))    {
  672.         int bbl = wnd->BlkBegLine;
  673.         int bel = wnd->BlkEndLine;
  674.         int bbc = wnd->BlkBegCol;
  675.         int bec = wnd->BlkEndCol;
  676.         int by = y;
  677.  
  678.         /* ----- put lowest marker first ----- */
  679.         if (bbl > bel)    {
  680.             swap(bbl, bel);
  681.             swap(bbc, bec);
  682.         }
  683.         if (bbl == bel && bbc > bec)
  684.             swap(bbc, bec);
  685.  
  686.         if (by >= bbl && by <= bel)    {
  687.             /* ------ the block includes this line ----- */
  688.             int blkbeg = 0;
  689.             int blkend = lnlen;
  690.             if (!(by > bbl && by < bel))    {
  691.                 /* --- the entire line is not in the block -- */
  692.                 if (by == bbl)
  693.                     /* ---- the block begins on this line --- */
  694.                     blkbeg = bbc;
  695.                 if (by == bel)
  696.                     /* ---- the block ends on this line ---- */
  697.                     blkend = bec;
  698.             }
  699.             if (blkend == 0 && lnlen == 0)    {
  700.                 strcpy(lp, " ");
  701.                 blkend++;
  702.             }
  703.             /* ----- insert the reset color token ----- */
  704.             memmove(lp+blkend+1,lp+blkend,strlen(lp+blkend)+1);
  705.             lp[blkend] = RESETCOLOR;
  706.             /* ----- insert the change color token ----- */
  707.             memmove(lp+blkbeg+3,lp+blkbeg,strlen(lp+blkbeg)+1);
  708.             lp[blkbeg] = CHANGECOLOR;
  709.             /* ----- insert the color tokens ----- */
  710.             SetReverseColor(wnd);
  711.             lp[blkbeg+1] = foreground | 0x80;
  712.             lp[blkbeg+2] = background | 0x80;
  713.             lnlen += 4;
  714.         }
  715.     }
  716.     /* - make sure left margin doesn't overlap color change - */
  717.     for (i = 0; i < wnd->wleft+3; i++)    {
  718.         if (*(lp+i) == '\0')
  719.             break;
  720.         if (*(unsigned char *)(lp + i) == RESETCOLOR)
  721.             break;
  722.     }
  723.     if (*(lp+i) && i < wnd->wleft+3)    {
  724.         if (wnd->wleft+4 > lnlen)
  725.             trunc = TRUE;
  726.         else 
  727.             lp += 4;
  728.     }
  729.     else     {
  730.         /* --- it does, shift the color change over --- */
  731.         for (i = 0; i < wnd->wleft; i++)    {
  732.             if (*(lp+i) == '\0')
  733.                 break;
  734.             if (*(unsigned char *)(lp + i) == CHANGECOLOR)    {
  735.                 *(lp+wnd->wleft+2) = *(lp+i+2);
  736.                 *(lp+wnd->wleft+1) = *(lp+i+1);
  737.                 *(lp+wnd->wleft) = *(lp+i);
  738.                 break;
  739.             }
  740.         }
  741.     }
  742.     /* ------ build the line to display -------- */
  743.     if (!trunc)    {
  744.         if (lnlen < wnd->wleft)
  745.             lnlen = 0;
  746.         else
  747.             lp += wnd->wleft;
  748.         if (lnlen > RectLeft(rc))    {
  749.             /* ---- the line exceeds the rectangle ---- */
  750.             int ct = RectLeft(rc);
  751.             char *initlp = lp;
  752.             /* --- point to end of clipped line --- */
  753.             while (ct)    {
  754.                 if (*(unsigned char *)lp == CHANGECOLOR)
  755.                     lp += 3;
  756.                 else if (*(unsigned char *)lp == RESETCOLOR)
  757.                     lp++;
  758.                 else
  759.                     lp++, --ct;
  760.             }
  761.             if (RectLeft(rc))    {
  762.                 char *lpp = lp;
  763.                 while (*lpp)    {
  764.                     if (*(unsigned char*)lpp==CHANGECOLOR)
  765.                         break;
  766.                     if (*(unsigned char*)lpp==RESETCOLOR) {
  767.                         lpp = lp;
  768.                         while (lpp >= initlp)    {
  769.                             if (*(unsigned char *)lpp ==
  770.                                             CHANGECOLOR) {
  771.                                 lp -= 3;
  772.                                 memmove(lp,lpp,3);
  773.                                 break;
  774.                             }
  775.                             --lpp;
  776.                         }
  777.                         break;
  778.                     }
  779.                     lpp++;
  780.                 }
  781.             }
  782.             lnlen = LineLength(lp);
  783.             len = min(lnlen, RectWidth(rc));
  784.             dif = strlen(lp) - lnlen;
  785.             len += dif;
  786.             if (len > 0)
  787.                 strncpy(line, lp, len);
  788.         }
  789.     }
  790.     /* -------- pad the line --------- */
  791.     while (len < RectWidth(rc)+dif)
  792.         line[len++] = ' ';
  793.     line[len] = '\0';
  794.     dif = 0;
  795.     /* ------ establish the line's main color ----- */
  796.     if (reverse)    {
  797.         char *cp = line;
  798.         SetReverseColor(wnd);
  799.         while ((cp = strchr(cp, CHANGECOLOR)) != NULL)    {
  800.             cp += 2;
  801.             *cp++ = background | 0x80;
  802.         }
  803.         if (*(unsigned char *)line == CHANGECOLOR)
  804.             dif = 3;
  805.     }
  806.     else
  807.         SetStandardColor(wnd);
  808.     /* ------- display the line -------- */
  809.     writeline(wnd, line+dif,
  810.                 RectLeft(rc)+BorderAdj(wnd),
  811.                     y-wnd->wtop+TopBorderAdj(wnd), FALSE);
  812.     free(svlp);
  813. }
  814.  
  815. void MarkTextBlock(WINDOW wnd, int BegLine, int BegCol,
  816.                                int EndLine, int EndCol)
  817. {
  818.     wnd->BlkBegLine = BegLine;
  819.     wnd->BlkEndLine = EndLine;
  820.     wnd->BlkBegCol = BegCol;
  821.     wnd->BlkEndCol = EndCol;
  822. }
  823.  
  824. /* ----- clear and initialize text line pointer array ----- */
  825. void ClearTextPointers(WINDOW wnd)
  826. {
  827.     wnd->TextPointers = DFrealloc(wnd->TextPointers, sizeof(int));
  828.     *(wnd->TextPointers) = 0;
  829. }
  830.  
  831. #define INITLINES 100
  832.  
  833. /* ---- build array of pointers to text lines ---- */
  834. void BuildTextPointers(WINDOW wnd)
  835. {
  836.     char *cp = wnd->text, *cp1;
  837.     int incrs = INITLINES;
  838.     unsigned int off;
  839.     wnd->textwidth = wnd->wlines = 0;
  840.     while (*cp)    {
  841.         if (incrs == INITLINES)    {
  842.             incrs = 0;
  843.             wnd->TextPointers = DFrealloc(wnd->TextPointers,
  844.                     (wnd->wlines + INITLINES) * sizeof(int));
  845.         }
  846.         off = (unsigned int) (cp - wnd->text);
  847.         *((wnd->TextPointers) + wnd->wlines) = off;
  848.         wnd->wlines++;
  849.         incrs++;
  850.         cp1 = cp;
  851.         while (*cp && *cp != '\n')
  852.             cp++;
  853.         wnd->textwidth = max(wnd->textwidth,
  854.                         (unsigned int) (cp - cp1));
  855.         if (*cp)
  856.             cp++;
  857.     }
  858. }
  859.  
  860. static void MoveScrollBox(WINDOW wnd, int vscrollbox)
  861. {
  862.     foreground = FrameForeground(wnd);
  863.     background = FrameBackground(wnd);
  864.     wputch(wnd, SCROLLBARCHAR, WindowWidth(wnd)-1,
  865.             wnd->VScrollBox+1);
  866.     wputch(wnd, SCROLLBOXCHAR, WindowWidth(wnd)-1,
  867.             vscrollbox+1);
  868.     wnd->VScrollBox = vscrollbox;
  869. }
  870.  
  871. int TextLineNumber(WINDOW wnd, char *lp)
  872. {
  873.     int lineno;
  874.     char *cp;
  875.     for (lineno = 0; lineno < wnd->wlines; lineno++)    {
  876.         cp = wnd->text + *((wnd->TextPointers) + lineno);
  877.         if (cp == lp)
  878.             return lineno;
  879.         if (cp > lp)
  880.             break;
  881.     }
  882.     return lineno-1;
  883. }
  884.  
  885.  
  886.