home *** CD-ROM | disk | FTP | other *** search
/ Piper's Pit BBS/FTP: ibm 0040 - 0049 / ibm0040-0049 / ibm0040.tar / ibm0040 / ZINC_6.ZIP / DOSSRC.ZIP / TEXT1.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1991-06-01  |  18.3 KB  |  823 lines

  1. //    Zinc Interface Library - TEXT1.CPP
  2. //    COPYRIGHT (C) 1990, 1991.  All Rights Reserved.
  3. //    Zinc Software Incorporated.  Pleasant Grove, Utah  USA
  4.  
  5. #pragma inline
  6.  
  7. #include "ui_win.hpp"
  8. #include <ctype.h>
  9. #include <stdio.h>
  10. #include <stdlib.h>
  11. #include <string.h>
  12.  
  13. #define    PIXEL_BORDER    2
  14. #define    TAB_STOP    8
  15. const short MAX_WIDTH = 128;
  16.  
  17. #define    TAB            9
  18. #define    LF           10
  19. #define    CR           13
  20.  
  21. USHORT LineChanged(char *newLine, char *oldLine, int  width);
  22.  
  23. #if 0
  24. char *AdvanceLine(char *ptr, USHORT numLines, int col, USHORT *actual,
  25.     int width)
  26. {
  27.     USHORT count = 0;
  28.  
  29.     while (numLines-- && *ptr)
  30.     {
  31.         char *row_start = ptr;
  32.         while (col < width && *ptr)
  33.         {
  34.             if (*ptr == '\t')
  35.             {
  36.                 col = (col + TAB_STOP) & ~(TAB_STOP - 1);
  37.                 ptr++;
  38.             }
  39.             else if (*ptr == '\r' || *ptr == '\n')
  40.             {
  41.                 ptr++;
  42.                 if (*(ptr - 1) == '\r' && *ptr == '\n')
  43.                     ptr++;
  44.                 count++;
  45.                 break;
  46.             }
  47.             else {
  48.                 ptr++;
  49.                 col++;
  50.             }
  51.         }
  52.         if (col >= width)                // Check for word wrap.
  53.         {
  54.             char *rover = ptr;
  55.             count++;
  56.             while (rover > row_start && *(rover - 1) != '\t' &&
  57.                 *(rover - 1) != ' ')
  58.                 rover--;
  59.             if (rover > row_start)
  60.                 ptr = rover;
  61.         }
  62.         col = 0;
  63.     }
  64.     if (actual)
  65.         *actual = count;
  66.     return ptr;
  67. }
  68. #endif
  69.  
  70. char *AdvanceLine(char *linePtr, USHORT numLines, int col, USHORT *actual,
  71.     int width)
  72. {
  73.         _CX = numLines;
  74.         _DX = 0;
  75.         _BL = col;
  76.         _BH = width;
  77. #if sizeof(linePtr) == 4
  78.         asm        push    ds
  79.         asm        lds        si, linePtr
  80. #else
  81.         asm        mov        si, linePtr
  82. #endif
  83.         asm        push    bp
  84.         asm        jmp        short whileNumLines
  85.  
  86. zeroColumn:
  87.         asm        mov        bl, 0
  88.  
  89. whileNumLines:
  90.         asm        jcxz    storeCount
  91.         asm        dec        cx
  92.  
  93.         asm        mov        bp, si                    // BP = row_start
  94.  
  95. whileSameLine:
  96.         asm        cmp        bl, bh
  97.         asm        jae        checkWrap
  98.  
  99.         asm        lodsb
  100.         asm        cmp        al, CR
  101.         asm        jbe        isCtrl
  102.  
  103. isReg:    asm        inc        bl
  104.         asm        jmp        whileSameLine
  105.  
  106. isCtrl:    asm        je        isCr
  107.  
  108.         asm        cmp        al, LF
  109.         asm        je        isLf
  110.  
  111.         asm        or        al, al
  112.         asm        je        isNull
  113.  
  114.         asm        cmp        al, TAB
  115.         asm        jne        isReg
  116.  
  117. isTab:    asm        add        bl, TAB_STOP
  118.         asm        and        bl, NOT (TAB_STOP - 1)
  119.         asm        jmp        whileSameLine
  120.  
  121. isCr:    asm        cmp        BYTE PTR [si], LF
  122.         asm        jne        isLf
  123.  
  124.         asm        inc        si
  125.  
  126. isLf:    asm        inc        dx
  127.         asm        jmp        short checkWrap
  128.  
  129. isNull:    asm        dec        si
  130.  
  131. checkWrap:
  132.         asm        cmp        bl, bh
  133.         asm        jb        zeroColumn
  134.  
  135.         asm        mov        di, si                    // DI = rover
  136.         asm        inc        dx                        // count++
  137.  
  138. wrap:    asm        cmp        di, bp
  139.         asm        jbe        zeroColumn
  140.  
  141.         asm        mov        al, [di - 1]
  142.         asm        cmp        al, TAB
  143.         asm        je        chkPtr
  144.  
  145.         asm        cmp        al, ' '
  146.         asm        je        chkPtr
  147.  
  148.         asm        dec        di
  149.         asm        jmp        wrap
  150.  
  151. chkPtr:    asm        cmp        di, bp
  152.         asm        jbe        zeroColumn
  153.  
  154.         asm        mov        si, di
  155.         asm        jmp        zeroColumn
  156.  
  157. storeCount:
  158.         asm        pop        bp
  159.         if (actual)
  160.             *actual = _DX;
  161.         asm        mov        WORD PTR linePtr, si
  162. #if sizeof(linePtr) == 4
  163.         asm        mov        WORD PTR linePtr + 2, ds
  164.         asm        pop        ds
  165. #endif
  166.         return linePtr;
  167. }
  168.  
  169. char *UIW_TEXT::AdvanceColumns(char *ptr, int num_cols, int *result_col)
  170. {
  171.     char *nextLine;
  172.     int col = 0;
  173.     USHORT count;
  174.  
  175.     nextLine = AdvanceLine(ptr, 1, 0, &count, width);
  176.     if (count == 0)
  177.         nextLine++;                        // Allow stopping on the trailing null.
  178.     while (col < num_cols && ptr < nextLine - 1 && *ptr != '\r' && *ptr != '\n')
  179.     {
  180.         if (*ptr == '\t')
  181.         {
  182.             col = (col + TAB_STOP) & ~(TAB_STOP - 1);
  183.             ptr++;
  184.         }
  185.         else
  186.         {
  187.             ptr++;
  188.             col++;
  189.         }
  190.     }
  191.     *result_col = col;
  192.     return ptr;
  193. }
  194.  
  195. void UIW_TEXT::BackspaceKey()
  196. {
  197.     if (cursor > text)
  198.     {
  199.         LeftArrow();
  200.         DeleteBlock(cursor, (*cursor == '\r' && *(cursor + 1) == '\n') ? 2 : 1);
  201.     }
  202. }
  203.  
  204. void UIW_TEXT::ComputeMousePosition(int mouse_col, int mouse_row)
  205. {
  206.     char *ptr = screenTop;
  207.     int row = 0;
  208.     int col = 0;
  209.     while (*ptr && row <= mouse_row)
  210.     {
  211.         USHORT count;
  212.         char *nextLine = AdvanceLine(ptr, 1, 0, &count, width);
  213.         while (*ptr && *ptr != '\r' && *ptr != '\n' && ptr < nextLine)
  214.         {
  215.             if (row == mouse_row && col >= mouse_col)
  216.                 break;
  217.             if (*ptr == '\t')
  218.             {
  219.                 col = (col + TAB_STOP) & ~(TAB_STOP - 1);
  220.                 ptr++;
  221.             }
  222.             else if (*ptr == '\0' || *ptr == '\r' || *ptr == '\n')
  223.                 ;
  224.             else
  225.             {
  226.                 col++;
  227.                 ptr++;
  228.             }
  229.         }
  230.         if (row == mouse_row && col >= mouse_col)
  231.             break;
  232.         row += count;
  233.         if (count)
  234.             col = 0;
  235.         if (row > mouse_row)
  236.             break;
  237.         ptr = nextLine;
  238.     }
  239.     if (row == mouse_row && col >= mouse_col || row > mouse_row)
  240.         cursor = ptr;
  241. }
  242.  
  243. void UIW_TEXT::ComputeRegion(int ccode, UI_REGION ®ion, UI_PALETTE *palette)
  244. {
  245.     UI_WINDOW_OBJECT::Border(ccode, region, palette);
  246.     pixelBorder = 0;
  247.     if (!display->isText && region.bottom - region.top > display->cellHeight)
  248.     {
  249.         while (pixelBorder < PIXEL_BORDER && region.top < region.bottom - 1 &&
  250.                region.left < region.right - 1)
  251.         {
  252.             region.top++;
  253.             region.bottom--;
  254.             region.left++;
  255.             region.right--;
  256.             pixelBorder++;
  257.         }
  258.     }
  259.     else if (!display->isText)
  260.         pixelBorder++;
  261.     height = (region.bottom + 1 - region.top) / cellHeight;
  262.     if (!display->isText)
  263.     {
  264.         int remainder = (region.bottom + 1 - region.top) % cellHeight;
  265.         if (remainder >= display->TextHeight("W"))
  266.             height++;
  267.     }
  268.     width = (region.right + 1 - region.left) / cellWidth;
  269.     if (width > MAX_WIDTH)
  270.         width = MAX_WIDTH;
  271. }
  272.  
  273. void UIW_TEXT::ComputeScroll()
  274. {
  275.     if (!previous)
  276.         return;
  277.  
  278.     char *ptr = text;
  279.     char *temp;
  280.  
  281.     if (FlagSet(woFlags, WOF_VIEW_ONLY))
  282.         cursor = screenTop;
  283.     USHORT count = 0;
  284.     USHORT totalLines;
  285.     while (ptr < cursor)
  286.     {
  287.         temp = AdvanceLine(ptr, 1, cursorCol, &totalLines, width);
  288.         if (temp != ptr)
  289.             ptr = temp;
  290.         else
  291.             break;
  292.         count += totalLines;
  293.     }
  294.     if (ptr != cursor && !FlagSet(woFlags, WOF_VIEW_ONLY))
  295.         count--;
  296.     AdvanceLine(text, 5000, 0, &totalLines, width);
  297.     UI_EVENT event;
  298.     event.type = S_SCROLL_VERTICAL_SET;
  299.     event.scroll.current = count;
  300.     event.scroll.showing = height;
  301.     event.scroll.maximum = FlagSet(woFlags, WOF_VIEW_ONLY) ? totalLines - height + 1 : totalLines;
  302.     if (event.scroll.maximum < event.scroll.showing)
  303.         event.scroll.showing = event.scroll.maximum;
  304.     Previous()->Event(event);
  305.     event.type = S_SCROLL_HORIZONTAL_SET;
  306.     event.scroll.current = event.scroll.showing = event.scroll.maximum = 1;
  307.     Previous()->Event(event);
  308. }
  309.  
  310. void UIW_TEXT::CopyBlock()
  311. {
  312.     while (screenTop >= markStart && screenTop > text)
  313.         screenTop = PreviousLine(screenTop, 1, 0, text);
  314.  
  315.     pasteLength = (int)(markTail - markStart);
  316.     if (pasteBuffer)
  317.         delete pasteBuffer;
  318.     pasteBuffer = new char[pasteLength];
  319.     memcpy(pasteBuffer, markStart, pasteLength);
  320.  
  321.     markedBlock = NULL;
  322. }
  323.  
  324. void UIW_TEXT::DeleteBlock(char *block, USHORT length)
  325. {
  326.     if (!length)
  327.         return;
  328.  
  329.     pasteLength = length;
  330.     if (pasteBuffer)
  331.         delete pasteBuffer;
  332.     pasteBuffer = new char[pasteLength];
  333.     memcpy(pasteBuffer, block, pasteLength);
  334.  
  335.     woStatus |= WOS_CHANGED | WOS_NO_AUTO_CLEAR;
  336.     strcpy(block, block + length);
  337.     cursorDesiredCol = -1;
  338.     cursor = block;
  339.     markedBlock = NULL;
  340. }
  341.  
  342. void UIW_TEXT::DeleteEol()
  343. {
  344.     char *nextLine;
  345.     char *rover;
  346.     USHORT count;
  347.  
  348.     nextLine = AdvanceLine(cursor, 1, cursorCol, 0, width);
  349.     rover = cursor;
  350.     while (*rover && *rover != '\r' && *rover != '\n' && rover < nextLine)
  351.         rover++;
  352.     count = (USHORT) (rover - cursor);
  353.     if (count)
  354.         DeleteBlock(cursor, count);
  355. }
  356.  
  357. void UIW_TEXT::DeleteWord()
  358. {
  359.     char *ptr;
  360.  
  361.     if (NonWhiteSpace(*cursor) || *cursor == ' ')
  362.     {
  363.         if (*cursor == ' ')
  364.         {
  365.             if (cursor == text || WhiteSpace(*(cursor - 1)))
  366.             {
  367.                 ptr = cursor;
  368.                 while (*ptr == ' ')
  369.                     ptr++;
  370.                 DeleteBlock(cursor, (USHORT) (ptr - cursor));
  371.                 return;                    /* NOTE: second return point here. */
  372.             }
  373.             WordTabLeft();
  374.         }
  375.         else
  376.         {
  377.             while (cursor > text && NonWhiteSpace(*(cursor - 1)))
  378.                 LeftArrow();
  379.         }
  380.         ptr = cursor;
  381.         while (NonWhiteSpace(*ptr))
  382.             ptr++;
  383.         while (*ptr == ' ')
  384.             ptr++;
  385.         DeleteBlock(cursor, (USHORT) (ptr - cursor));
  386.     }
  387. }
  388.  
  389. void UIW_TEXT::EnterKey()
  390. {
  391.     static char cr_lf[2] = { '\r', '\n' };
  392.  
  393.     if (strchr(cursor, '\0') < textTail - 1)
  394.         InsertBlock(cursor, cr_lf, 2);
  395. }
  396.  
  397. void UIW_TEXT::Home()
  398. {
  399.     char *previousLine = PreviousLine(cursor, 1, cursorCol, text);
  400.     cursor = (previousLine) ? AdvanceLine(previousLine, 1, 0, 0, width) : text;
  401.     cursorDesiredCol = 0;
  402. }
  403.  
  404. void UIW_TEXT::InsertBlock(char *insertPoint, char *block, USHORT length)
  405. {
  406.     woStatus |= (WOS_CHANGED | WOS_NO_AUTO_CLEAR);
  407.     memmove(insertPoint + length, insertPoint, strlen(insertPoint) + 1);
  408.     memcpy(insertPoint, block, length);
  409.     if (insertPoint == cursor)
  410.         cursor += length;
  411.     cursorDesiredCol = -1;
  412. }
  413.  
  414. int UIW_TEXT::LastLine()
  415. {
  416.     short col = cursorCol;
  417.     char *ptr = cursor;
  418.  
  419.     while (col < width && *ptr && *ptr != '\r' && *ptr != '\n')
  420.     {
  421.         if (*ptr == '\t')
  422.         {
  423.             col = (col + TAB_STOP) & ~(TAB_STOP - 1);
  424.             ptr++;
  425.         }
  426.         else
  427.         {
  428.             ptr++;
  429.             col++;
  430.         }
  431.     }
  432.     return (*ptr == '\0' ? TRUE : FALSE);
  433. }
  434.  
  435. void UIW_TEXT::LeftArrow()
  436. {
  437.     if (cursor > text)
  438.     {
  439.         cursor--;
  440.         if (*cursor == '\n' && cursor > text &&    *(cursor - 1) == '\r')
  441.             cursor--;
  442.         if (cursor < screenTop)
  443.             screenTop = PreviousLine(screenTop, 1, 0, text);
  444.         cursorDesiredCol = -1;
  445.     }
  446. }
  447.  
  448. #pragma argsused
  449. void UIW_TEXT::MoveDown(USHORT numLines, int ccode)
  450. {
  451.     char *nextLine;
  452.     int col;
  453.     int row;
  454.  
  455.     row = cursorRow;
  456.     col = cursorCol;
  457.     int totalLines = 0;
  458.     int viewLines = 0;
  459.     while (numLines--)
  460.     {
  461.         nextLine = AdvanceLine(cursor, 1, col, 0, width);
  462.         if (*nextLine || (nextLine > cursor &&
  463.             (*(nextLine - 1) == '\r' || *(nextLine - 1) == '\n')))
  464.         {
  465.             /* There is a line to advance to. */
  466.             totalLines++;
  467.             row++;
  468.             cursor = AdvanceColumns(nextLine, cursorDesiredCol, &col);
  469.             if (row >= height)
  470.             {
  471.                 screenTop = AdvanceLine(screenTop, 1, 0, 0, width);
  472.                 viewLines++;
  473.                 row--;
  474.             }
  475.         }
  476.         else
  477.             break;
  478.     }
  479. }
  480.  
  481. #pragma argsused
  482. void UIW_TEXT::MoveUp(USHORT numLines, int ccode)
  483. {
  484.     char *nextLine;
  485.     int col;
  486.  
  487.     col = cursorCol;
  488.     int totalLines = 0;
  489.     int viewLines = 0;
  490.     while (numLines--)
  491.     {
  492.         nextLine = PreviousLine(cursor, 1, col, text);
  493.         if (nextLine)
  494.         {
  495.             totalLines++;
  496.             cursor = AdvanceColumns(nextLine, cursorDesiredCol, &col);
  497.             if (nextLine < screenTop)
  498.             {
  499.                 screenTop = nextLine;
  500.                 viewLines++;
  501.             }
  502.         }
  503.         else
  504.             break;
  505.     }
  506.  
  507.     if (previous && totalLines)
  508.     {
  509.         UI_WINDOW_OBJECT *object = Previous();
  510.         UI_EVENT event;
  511.         event.type = S_SCROLL_VERTICAL;
  512.         event.scroll.delta = FlagSet(woFlags, WOF_VIEW_ONLY) ? viewLines : totalLines;
  513.         object->Event(event);
  514.     }
  515. }
  516.  
  517. void UIW_TEXT::PasteBlock()
  518. {
  519.     if (pasteBuffer && (!markedBlock || markedBlock == cursor) &&
  520.         pasteLength <= textTail - strchr(cursor, '\0'))
  521.     {
  522.         markedBlock = 0;
  523.         InsertBlock(cursor, pasteBuffer, pasteLength);
  524.     }
  525. }
  526.  
  527. char *UIW_TEXT::PreviousLine(char *line, USHORT numLines, int col, char *base)
  528. {
  529.     char *base_line;
  530.     char *rover;
  531.     USHORT baseDelta;
  532.     USHORT maxDelta;
  533.     USHORT lineNum;
  534.     USHORT count;
  535.                  
  536.     baseDelta = (USHORT) (line - base);
  537.     maxDelta = numLines * (width + 2) + col + 2;
  538.     if (maxDelta < baseDelta)
  539.     {
  540.         rover = line - maxDelta;
  541.         while (rover > base && *(rover - 1) != '\n' && *(rover - 1) != '\r')
  542.             rover--;
  543.         base_line = rover;
  544.     }
  545.     else
  546.         base_line = base;
  547.     rover = base_line;
  548.     lineNum = 0;
  549.     while (rover <= line)
  550.     {
  551.         rover = AdvanceLine(rover, 1, 0, &count, width);
  552.         lineNum++;
  553.         if (count == 0 && *rover == '\0')
  554.             break;
  555.     }
  556.     if (lineNum < numLines + 1)
  557.         return 0;
  558.     else
  559.         return AdvanceLine(base_line, lineNum - numLines - 1, 0, 0, width);
  560. }
  561.  
  562. void UIW_TEXT::Redisplay(UI_REGION ®ion, int ccode)
  563. {
  564.     USHORT count;
  565.     char line[MAX_WIDTH];
  566.     char xor[MAX_WIDTH];
  567.     cursorRow = -1;
  568.     if (FlagSet(woStatus, WOS_UNANSWERED))
  569.     {
  570.         text[0] = '\0';
  571.         cursor = text;
  572.         screenTop = text;
  573.         textNull = text;
  574.         markedBlock = 0;
  575.         cursorDesiredCol = -1;
  576.     }
  577.     int newScreenSize = height * width;
  578.     if (newScreenSize > screenSize)
  579.     {
  580.         if (screen)
  581.             delete screen;
  582.         screen = 0;
  583.     }
  584.     if (!screen)
  585.     {
  586.         screen = new char[newScreenSize];
  587.         screenSize = newScreenSize;
  588.         screenInvalid = TRUE;
  589.     }
  590.     if (screenInvalid)
  591.     {
  592.         memset(screen, '\1', screenSize);
  593.         if (!display->isText)
  594.         {
  595.             UI_REGION border = region;
  596.             UI_PALETTE tPalette = *lastPalette;
  597.             tPalette.colorForeground = tPalette.colorBackground;
  598.             tPalette.bwForeground = tPalette.bwBackground;
  599.             tPalette.grayScaleForeground = tPalette.grayScaleBackground;
  600.             for (int i = 0; i < pixelBorder; i++)
  601.             {
  602.                 border.top--;
  603.                 border.bottom++;
  604.                 border.left--;
  605.                 border.right++;
  606.                 display->Rectangle(screenID, border, &tPalette);
  607.             }
  608.         }
  609.     }
  610.     SetMark();
  611.     char *newMarkStart = 0;
  612.     char *newMarkTail = 0;
  613.     char *ptr = screenTop;
  614.     int row = 0;
  615.     int rowWidth = 0;
  616.     if (markStart && ptr >= markStart)
  617.         newMarkStart = screen;
  618.     if (width <= 0)
  619.     {
  620.         if (!display->isText)
  621.             display->Rectangle(screenID, region, lastPalette, 0, TRUE);
  622.         return;
  623.     }
  624.  
  625.     while (row < height)
  626.     {
  627.         int markLine = FALSE;
  628.         int markLeft = width - 1;
  629.         int markRight = 0;
  630.         int col = 0;
  631.         char *nextLine = AdvanceLine(ptr, 1, 0, &count, width);
  632.         while (*ptr != '\r' && *ptr != '\n' && ptr < nextLine)
  633.         {
  634.             if (markedBlock)
  635.             {
  636.                 if (ptr >= markStart && ptr < markTail)
  637.                 {
  638.                     if (ptr == markStart)
  639.                         newMarkStart = screen + rowWidth + col;
  640.                     markLine = TRUE;
  641.                     if (col < markLeft)
  642.                         markLeft = col;
  643.                     if (col > markRight)
  644.                         markRight = col;
  645.                 }
  646.                 else if (ptr == markTail)
  647.                     newMarkTail = screen + rowWidth + col;
  648.             }
  649.             if (ptr == cursor)
  650.             {
  651.                 cursorRow = row;
  652.                 cursorCol = col;
  653.             }
  654.             if (*ptr == '\t')
  655.             {
  656.                 int newCol = (col + TAB_STOP) & ~(TAB_STOP - 1);
  657.                 memset(&line[col], ' ', newCol - col);
  658.                 col = newCol;
  659.                 ptr++;
  660.             }
  661.             else
  662.                 line[col++] = *ptr++;
  663.         }
  664.         if (col > width)       // Necessary due to TAB at end of line possibility.
  665.             col = width;
  666.         if (ptr == cursor && cursorRow == -1)
  667.         {
  668.             cursorRow = row;
  669.             cursorCol = col;
  670.         }
  671.         memset(&line[col], '\0', width - col);
  672.         if (ptr == markStart && !newMarkStart)
  673.             newMarkStart = screen + rowWidth + col;
  674.         else if (ptr == markTail && !newMarkTail)
  675.             newMarkTail = screen + rowWidth + col;
  676.         memset(xor,  '\0', width);
  677.         int nextRowWidth = rowWidth + width;        // (row + 1) * width
  678.         if (screenMarkStart && screenMarkStart < screen + nextRowWidth &&
  679.             screenMarkTail > screen + rowWidth)
  680.         {
  681.             int lineStart = 0;
  682.             if (screenMarkStart > screen + rowWidth)
  683.                 lineStart = (int) (screenMarkStart - (screen + rowWidth));
  684.             int lineTail = Min(col, width);
  685.             if (screenMarkTail < screen + nextRowWidth)
  686.                 lineTail = (int) (screenMarkTail - (screen + rowWidth));
  687.             if (lineTail > lineStart)
  688.                 memset(&xor[lineStart], 1, lineTail - lineStart);
  689.         }
  690.         _DX = LineChanged(line, screen + rowWidth, width);
  691.         if (_DX != 0xFFFF)
  692.         {
  693.             int leftCol = _DL;
  694.             int rightCol = _DH;
  695.             // Re-displaying will wipe out mark.
  696.             memset(&xor[leftCol], '\0', rightCol + 1 - leftCol);
  697.             if (!display->isText)        // Pre-fill for graphics.
  698.             {
  699.                 int topPixel = region.top + row * cellHeight;
  700.                 int bottomPixel = topPixel + cellHeight - 1;
  701.                 if (bottomPixel > true.bottom - pixelBorder)
  702.                     bottomPixel = true.bottom - pixelBorder;
  703.                 display->Rectangle(screenID, region.left + leftCol * cellWidth,
  704.                     topPixel, rightCol == width - 1 ? region.right :
  705.                     region.left + (rightCol + 1) * cellWidth - 1,
  706.                     bottomPixel, lastPalette, 0, TRUE);
  707.             }
  708.             display->Text(screenID, region.left + leftCol * cellWidth,
  709.                 region.top + row * cellHeight, &line[leftCol],
  710.                 lastPalette, rightCol + 1 - leftCol, FALSE);
  711.         }
  712.         if (markLine)
  713.         {
  714.             for (int i = markLeft; i <= markRight; i++)
  715.                 xor[i] ^= 1;
  716.         }
  717.         char *xorStart = xor;
  718.         while ((xorStart = (char *) memchr(xorStart, '\1', (int) (xor + width - xorStart))) != 0)
  719.         {
  720.             int leftXor = (int) (xorStart - xor);
  721.             int rightXor = leftXor;
  722.             while (rightXor < width - 1 && xor[rightXor + 1])
  723.                 rightXor++;
  724.             display->Text(screenID, region.left + leftXor * cellWidth,
  725.                 region.top + row * cellHeight, NULL, _xorPalette,
  726.                 rightXor + 1 - leftXor, TRUE, TRUE);
  727.             xorStart = xor + rightXor + 1;
  728.         }
  729.         ptr = nextLine;
  730.         row += count;
  731.         if (count)
  732.             col = 0;
  733.         if (!newMarkStart && ptr == markStart)
  734.             newMarkStart = screen + row * width + col;
  735.         else if (!newMarkTail && ptr == markTail)
  736.             newMarkTail = screen + row * width + col;
  737.         if (ptr == cursor && cursorRow == -1)
  738.         {
  739.             cursorRow = row;
  740.             cursorCol = col;
  741.         }
  742.         if (!count)
  743.             row++;
  744.         rowWidth += width;
  745.     }
  746.  
  747.     if (ptr <= markTail && !newMarkTail)
  748.         newMarkTail = screen + rowWidth;      // Point just past end of screen.
  749.     if (screenInvalid)
  750.     {
  751.         screenInvalid = FALSE;
  752.         if (!display->isText &&
  753.             region.top + height * cellHeight <= region.bottom)
  754.             display->Rectangle(screenID, region.left,
  755.                 region.top + height * cellHeight, region.right,
  756.                 region.bottom, lastPalette, 0, TRUE);
  757.     }
  758.     if (cursorRow == -1)
  759.     {
  760.         cursorRow = 0;
  761.         cursorCol = 0;
  762.     }
  763.     if (cursorDesiredCol == -1)
  764.         cursorDesiredCol = cursorCol;
  765.     screenMarkStart = newMarkStart;
  766.     screenMarkTail = newMarkTail;
  767.     if (ccode != S_DISPLAY_INACTIVE)
  768.         UpdateCursor(region);
  769. }
  770.  
  771. void UIW_TEXT::RegularKey(USHORT key)
  772. {
  773.     if (FlagSet(woFlags, WOF_AUTO_CLEAR) &&
  774.         !FlagSet(woStatus, WOS_NO_AUTO_CLEAR) && cursor == text && *text)
  775.         DeleteBlock(text, strlen(text));
  776.     if (insertMode || *cursor == '\r' || *cursor == '\n' || *cursor == '\0')
  777.     {
  778.         if (strchr(cursor, '\0') < textTail)
  779.             InsertBlock(cursor, (char *)&key, 1);
  780.     }
  781.     else if (cursor < textTail)
  782.         ReplaceChar(cursor, key);
  783. }
  784.  
  785. void UIW_TEXT::ReplaceChar(char *buff, USHORT key)
  786. {
  787.     woStatus |= WOS_CHANGED | WOS_NO_AUTO_CLEAR;
  788.     *buff = key;
  789.     if (buff == cursor)
  790.         cursor++;
  791.     cursorDesiredCol = -1;
  792. }
  793.  
  794. void UIW_TEXT::UpdateCursor(UI_REGION ®ion)
  795. {
  796.     if (FlagSet(woStatus, WOS_CURRENT) && !FlagSet(woFlags, WOF_VIEW_ONLY) &&
  797.          !FlagSet(woAdvancedStatus, WOAS_TOO_SMALL))
  798.     {
  799.         int col = cursorCol * cellWidth;
  800.         int row = cursorRow * cellHeight;
  801.  
  802.         if (region.left + col >= 0 && region.left + col < display->columns &&
  803.             region.top  + row >= 0 && region.top  + row < display->lines)
  804.         {
  805.             eventManager->DevicePosition(E_CURSOR, region.left + col, region.top + row);
  806.             eventManager->DeviceState(E_CURSOR,
  807.                 insertMode ? DC_INSERT : DC_OVERTYPE);
  808.         }
  809.     }
  810. }
  811.  
  812. void UIW_TEXT::WordTabLeft()
  813. {
  814.     while (cursor > text && WhiteSpace(*(cursor - 1)))
  815.         cursor--;
  816.     while (cursor > text && NonWhiteSpace(*(cursor - 1)))
  817.         cursor--;
  818.     while (cursor < screenTop)
  819.         screenTop = PreviousLine(screenTop, 1, 0, text);
  820.     cursorDesiredCol = -1;
  821. }
  822.  
  823.