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