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 / STRING1.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1991-06-01  |  12.0 KB  |  485 lines

  1. //    Zinc Interface Library - STRING1.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 <string.h>
  10.  
  11. #if 0
  12.  
  13. // Original C version of the "LineChanged" routine below.
  14. USHORT LineChanged(char *newLine, char *oldLine, int width)
  15. {
  16.     if (width > 0)
  17.     {
  18.         int leftCol = 0;
  19.         int rightCol = width - 1;
  20.         while (leftCol <= rightCol && newLine[leftCol] == oldLine[leftCol])
  21.             leftCol++;
  22.         while (leftCol <= rightCol && newLine[rightCol] == oldLine[rightCol])
  23.             rightCol--;
  24.         if (leftCol <= rightCol)
  25.         {
  26.             memcpy(&oldLine[leftCol], &newLine[leftCol], rightCol + 1 - leftCol);
  27.             return leftCol + (rightCol << 8);
  28.         }
  29.     }
  30.     return 0xFFFF;
  31. }
  32. #endif
  33.  
  34. /* LineChanged -
  35.  *        Compare a line of text about to be written to the screen with the
  36.  *        saved copy of that line to see if there are any changes.  If so,
  37.  *        return the leftmost column of the changed area in the low order
  38.  *        byte, and the rightmost column of the changed area in the high order
  39.  *        byte.  If the line has not changed, return -1 (0xFFFF).
  40.  */
  41. USHORT LineChanged(char *newLine, char *oldLine, int width)
  42. {
  43. #if sizeof(newLine) == 4
  44.     asm        push    ds
  45.     asm        lds        si, newLine
  46.     asm        les        di, oldLine
  47. #else
  48.     asm        mov        si, newLine
  49.     asm        push    ds
  50.     asm        pop        es
  51.     asm        mov        di, oldLine
  52. #endif
  53.     asm        mov        ax, 0FFFFH        // Preset for "no change" (-1) return.
  54.     asm        mov        cx, width
  55.     asm        cmp        cx, 0
  56.     asm        jle        done
  57.  
  58.     asm        repe    cmpsb
  59.     asm        je        done            // Return -1 if no change in the line.
  60.  
  61.     asm        dec        si                // Point back to first non-match
  62.     asm        dec        di                // ""
  63.     asm        mov        bx, si            // Save copy of ptr to first non-match
  64.     asm        add        si, cx            // Point to last character
  65.     asm        add        di, cx            //   "   "   "       "
  66.     asm        mov        cx, width
  67.     asm        std
  68.     asm        repe    cmpsb
  69.     asm        inc        si                // Point to last non-match
  70.     asm        inc        di                //   "   "    "     "
  71.     asm        mov        ah, cl            // Save copy of rightCol in AH
  72.     asm        mov        cx, si
  73.     asm        inc        cx
  74.     asm        sub        cx, bx            // CX has number of different bytes.
  75.     asm        mov        al, ah        
  76.     asm        inc        al
  77.     asm        sub        al, cl            // AL = leftCol = rightCol + 1 - count
  78.     asm        rep        movsb            // Update copy of old line
  79.     asm        cld
  80.  
  81. done:
  82. #if sizeof(newLine) == 4
  83.     asm        pop        ds
  84. #endif
  85.     return _AX;
  86. }
  87.  
  88. void UIW_STRING::DataSet(char *newText, short maxLength)
  89. {
  90.     if (newText)
  91.     {
  92.         short oldMaxLength = (short)(textTail + 1 - text);
  93.         if (FlagSet(woFlags, WOF_NO_ALLOCATE_DATA))
  94.             text = newText;
  95.         else
  96.         {
  97.             if (maxLength != -1 && maxLength > oldMaxLength)
  98.             {
  99.                 delete text;
  100.                 text = new char[maxLength];
  101.             }
  102.             int srcLen = strlen(newText) + 1;
  103.             int realMaxLength = (maxLength == -1) ? oldMaxLength : maxLength;
  104.             memcpy(text, newText, Min(srcLen, realMaxLength));
  105.         }
  106.         if (maxLength != -1)
  107.             textTail = text + maxLength - 1;
  108.         else
  109.             textTail = text + oldMaxLength - 1;
  110.         *textTail = '\0';                        // Insure trailing null.
  111.         screenTop = text;
  112.         cursor = text;
  113.         markedBlock = 0;
  114.     }
  115.     UI_WINDOW_OBJECT::Redisplay(FALSE);
  116. }
  117.  
  118. void UIW_STRING::BackspaceKey()
  119. {
  120.     if (cursor > text)
  121.     {
  122.         LeftArrow();
  123.         DeleteBlock(cursor, 1);
  124.         CheckLeftScroll();
  125.     }
  126. }
  127.  
  128. int UIW_STRING::CalcLeading(int width)
  129. {
  130.     int textLen = strlen(screenTop);
  131.     int leading = 0;
  132.     if (textLen < fieldWidth - 1)
  133.     {
  134.         if (woFlags & WOF_JUSTIFY_CENTER)
  135.             leading = Min((fieldWidth - 1 - textLen) / 2, width);
  136.         else if (woFlags & WOF_JUSTIFY_RIGHT)
  137.             leading = Min(fieldWidth - 1 - textLen, width);
  138.     }
  139.     return leading;
  140. }
  141.  
  142. void UIW_STRING::CheckLeftScroll()
  143. {
  144.     if (cursor <= screenTop && screenTop > text)
  145.         screenTop = Max(text, cursor - fieldWidth / 3);
  146. }
  147.  
  148. void UIW_STRING::CheckRightScroll()
  149. {
  150.     if (cursor - screenTop >= fieldWidth)
  151.     {
  152.         char *maxScreenTop = textTail + 1 - fieldWidth;
  153.         screenTop = Min(maxScreenTop, cursor + 1 - fieldWidth + fieldWidth / 3);
  154.     }
  155. }
  156.  
  157. void UIW_STRING::CopyBlock()
  158. {
  159.     if (screenTop >= markStart && screenTop > text)
  160.         screenTop = markStart;
  161.  
  162.     pasteLength = (int)(markTail - markStart);
  163.     if (pasteBuffer)
  164.         delete pasteBuffer;
  165.     pasteBuffer = new char[pasteLength];
  166.     memcpy(pasteBuffer, markStart, pasteLength);
  167.  
  168.     markedBlock = NULL;
  169. }
  170.  
  171. void UIW_STRING::DeleteBlock(char *block, USHORT length)
  172. {
  173.     if (!length)
  174.         return;
  175.  
  176.     pasteLength = length;
  177.     if (pasteBuffer)
  178.         delete pasteBuffer;
  179.     pasteBuffer = new char[pasteLength];
  180.     memcpy(pasteBuffer, block, pasteLength);
  181.  
  182.     woStatus |= WOS_CHANGED | WOS_NO_AUTO_CLEAR;
  183.     memmove(block, block + length, (size_t)(textNull + 1 - (block + length)));
  184.     textNull -= length;
  185.     cursor = block;
  186.     markedBlock = NULL;
  187. }
  188.  
  189. void UIW_STRING::DeleteEol()
  190. {
  191.     char *rover;
  192.     USHORT count;
  193.  
  194.     rover = strchr(cursor, '\0');
  195.     count = (USHORT) (rover - cursor);
  196.     if (count)
  197.         DeleteBlock(cursor, count);
  198. }
  199.  
  200. void UIW_STRING::DeleteWord()
  201. {
  202.     char *ptr;
  203.  
  204.     if (*cursor)
  205.     {
  206.         if (*cursor == ' ')
  207.         {
  208.             if (cursor == text || WhiteSpace(*(cursor - 1) ) )
  209.             {
  210.                 ptr = cursor;
  211.                 while (*ptr == ' ')
  212.                     ptr++;
  213.                 DeleteBlock(cursor, (USHORT) (ptr - cursor) );
  214.                 return;                    /* NOTE: second return point here. */
  215.             }
  216.             WordTabLeft();
  217.         }
  218.         else
  219.         {
  220.             while ( cursor > text && NonWhiteSpace(*(cursor - 1) ) )
  221.                 LeftArrow();
  222.         }
  223.         ptr = cursor;
  224.         while ( NonWhiteSpace(*ptr) )
  225.             ptr++;
  226.         while (*ptr == ' ')
  227.             ptr++;
  228.         DeleteBlock(cursor, (USHORT) (ptr - cursor) );
  229.     }
  230. }
  231.  
  232. void UIW_STRING::InsertBlock(char *insert_point, char *block, USHORT length)
  233. {
  234.     if (length)
  235.     {
  236.         woStatus |= WOS_CHANGED | WOS_NO_AUTO_CLEAR;
  237.         memmove(insert_point + length, insert_point,
  238.             (size_t) (textNull + 1 - insert_point) );
  239.         memcpy(insert_point, block, length);
  240.         textNull += length;
  241.         if (insert_point == cursor)
  242.             cursor += length;
  243.     }
  244. }
  245.  
  246. void UIW_STRING::LeftArrow()
  247. {
  248.     if (cursor > text)
  249.     {
  250.         cursor--;
  251.         if (cursor < screenTop)
  252.             screenTop--;
  253.     }
  254. }
  255.  
  256. void UIW_STRING::PasteBlock()
  257. {
  258.     if (pasteBuffer && !markedBlock &&
  259.         pasteLength <= textTail - textNull)
  260.         InsertBlock(cursor, pasteBuffer, pasteLength);
  261. }
  262.  
  263. void UIW_STRING::Redisplay(int ccode)
  264. {
  265.     UI_REGION region;
  266.     UI_WINDOW_OBJECT::Border(0, region, 0);
  267.     short cellWidth = display->TextWidth("W");
  268.     short cellHeight = display->TextHeight("W");
  269.     short width = (region.right + 1 - region.left) / cellWidth;
  270.     char line[133];
  271.     char xor[133];
  272.     if (FlagSet(woStatus, WOS_UNANSWERED))
  273.     {
  274.         text[0] = '\0';
  275.         cursor = text;
  276.         screenTop = text;
  277.         textNull = text;
  278.         markedBlock = 0;
  279.     }
  280.     int newScreenSize = width;
  281.     if (newScreenSize > screenSize)
  282.     {
  283.         if (screen)
  284.             delete screen;
  285.         screen = 0;
  286.     }
  287.     if (!screen)
  288.     {
  289.         screen = new char[newScreenSize];
  290.         screenSize = newScreenSize;
  291.         screenInvalid = TRUE;
  292.     }
  293.     if (screenInvalid)
  294.         memset(screen, '\1', screenSize);
  295.     char *newMarkStart = 0;
  296.     char *newMarkTail = 0;
  297.     char *ptr = screenTop;
  298.     int markLine = FALSE;
  299.     int markLeft = width - 1;
  300.     int textLen = strlen(screenTop);
  301.     int leading = CalcLeading(width);
  302.     textLen = Min(textLen, width - leading);
  303.     memset(line, ' ', leading);
  304.     int col = leading;
  305.     int markRight = col;
  306.     if (width <= 0)
  307.     {
  308.         if (!display->isText)
  309.             display->Rectangle(screenID, region, lastPalette, 0, TRUE);
  310.     }
  311.     else
  312.     {
  313.         while (*ptr && col < width)
  314.         {
  315.             if (markedBlock)
  316.             {
  317.                 if (ptr >= markStart && ptr < markTail)
  318.                 {
  319.                     if (ptr == markStart)
  320.                         newMarkStart = screen + col;
  321.                     markLine = TRUE;
  322.                     if (col < markLeft)
  323.                         markLeft = col;
  324.                     if (col > markRight)
  325.                         markRight = col;
  326.                 }
  327.                 else if (ptr == markTail)
  328.                     newMarkTail = screen + col;
  329.             }
  330.             line[col++] = *ptr++;
  331.         }
  332.         memset(&line[col], '\0', width - col);
  333.         if (ptr == markStart && !newMarkStart)
  334.             newMarkStart = screen + col;
  335.         else if (ptr == markTail && !newMarkTail)
  336.             newMarkTail  = screen + col;
  337.         memset(xor,  '\0', width);
  338.         if (screenMarkStart && screenMarkStart < screen + width &&
  339.             screenMarkTail > screen)
  340.         {
  341.             int lineStart = 0;
  342.             if (screenMarkStart > screen)
  343.                 lineStart = (int) (screenMarkStart - screen);
  344.             int lineTail = Min(col, width);
  345.             if (screenMarkTail < screen + width)
  346.                 lineTail = (int) (screenMarkTail - screen);
  347.             memset(&xor[lineStart], '\1', lineTail - lineStart);
  348.         }
  349.         int vertOffset = VerticalCenterOffset(®ion);
  350.         if (region.bottom >= region.top + cellHeight - 1)
  351.         {
  352.             _DX = LineChanged(line, screen, width);
  353.             if (_DX != 0xFFFF)
  354.             {
  355.                 int leftCol  = _DL;
  356.                 int rightCol = _DH;
  357.                 // Re-displaying will wipe out mark.
  358.                 memset(&xor[leftCol], '\0', rightCol + 1 - leftCol);
  359.                 if ( !display->isText )        // Pre-fill for graphics.
  360.                 {
  361.                     display->Rectangle(screenID,
  362.                         region.left + leftCol * cellWidth, region.top,
  363.                         rightCol == width - 1 ? region.right :
  364.                         region.left + (rightCol + 1) * cellWidth - 1,
  365.                         region.bottom, lastPalette, 0, TRUE);
  366.                 }
  367.                 display->Text(screenID,
  368.                     region.left + leftCol * cellWidth,
  369.                     region.top + vertOffset, &line[leftCol],
  370.                     lastPalette, rightCol + 1 - leftCol, FALSE);
  371.             }
  372.             if (markLine)
  373.             {
  374.                 for (int i = markLeft; i <= markRight; i++)
  375.                     xor[i] ^= 1;
  376.             }
  377.             char *xorStart = xor;
  378.             while ( (xorStart = (char *) memchr(xorStart, '\1', (int) (xor + width - xorStart))) != 0 )
  379.             {
  380.                 int leftXor = (int) (xorStart - xor);
  381.                 int rightXor = leftXor;
  382.                 while (rightXor < width - 1 && xor[rightXor + 1])
  383.                     rightXor++;
  384.                 display->Text(screenID, region.left + leftXor * cellWidth,
  385.                     region.top + vertOffset, NULL, _xorPalette,
  386.                     rightXor + 1 - leftXor, TRUE, TRUE);
  387.                 xorStart = xor + rightXor + 1;
  388.             }
  389.             if (!newMarkStart && ptr == markStart)
  390.                 newMarkStart = screen + col;
  391.             else if (!newMarkTail && ptr == markTail)
  392.                 newMarkTail  = screen + col;
  393.         }
  394.         else if (screenInvalid)
  395.         {
  396.             // We are in graphics mode with not enough height to display text.
  397.             display->Rectangle(screenID, region, lastPalette, 0, TRUE);
  398.         }
  399.         screenInvalid = FALSE;
  400.         screenMarkStart = newMarkStart;
  401.         screenMarkTail  = newMarkTail;
  402.         if (ccode != S_DISPLAY_INACTIVE)
  403.             UpdateCursor(region, width);
  404.     }
  405. }
  406.  
  407. void UIW_STRING::RegularKey(USHORT key)
  408. {
  409.     if (FlagSet(woFlags, WOF_AUTO_CLEAR) &&
  410.         !FlagSet(woStatus, WOS_NO_AUTO_CLEAR) && cursor == text && *text)
  411.     {
  412.         DeleteBlock(text, strlen(text));
  413.         textNull = text;
  414.     }
  415.     if (insertMode || cursor == textNull)
  416.     {
  417.         if (textNull < textTail)
  418.             InsertBlock(cursor, (char *) &key, 1);
  419.     }
  420.     else if (cursor < textTail)
  421.         ReplaceChar(cursor, key);
  422.     CheckRightScroll();
  423. }
  424.  
  425. void UIW_STRING::ReplaceChar(char *buff, USHORT key)
  426. {
  427.     woStatus |= WOS_CHANGED | WOS_NO_AUTO_CLEAR;
  428.     *buff = key;
  429.     if (buff == cursor)
  430.         cursor++;
  431. }
  432.  
  433. void UIW_STRING::SetMark()
  434. {
  435.     markStart = markTail = 0;
  436.     if (markedBlock)
  437.     {
  438.         if (markedBlock > cursor)
  439.         {
  440.             markStart = cursor;
  441.             markTail  = markedBlock;
  442.         }
  443.         else if (markedBlock < cursor)
  444.         {
  445.             markStart = markedBlock;
  446.             markTail  = cursor;
  447.         }
  448.     }
  449. }
  450.  
  451. void UIW_STRING::UpdateCursor(UI_REGION ®ion, int width)
  452. {
  453.     int cursorColumn = (int)(cursor - screenTop);
  454.     int leading = CalcLeading(width);
  455.     int trueColumn = region.left + (leading + cursorColumn) * display->TextWidth("W");
  456.     if ( FlagSet(woStatus, WOS_CURRENT) && !FlagSet(woFlags, WOF_VIEW_ONLY) &&
  457.          !FlagSet(woAdvancedStatus, WOAS_TOO_SMALL) &&
  458.         trueColumn >= 0 && 
  459.         trueColumn < display->columns && region.top >= 0 && 
  460.         region.top  < display->lines && leading + cursorColumn < width)
  461.     {
  462.         eventManager->DevicePosition(E_CURSOR, trueColumn, region.top + VerticalCenterOffset(®ion) );
  463.         eventManager->DeviceState(E_CURSOR, (insertMode ? DC_INSERT : DC_OVERTYPE));
  464.     }
  465. }
  466.  
  467. int UIW_STRING::VerticalCenterOffset(UI_REGION *region)
  468. {
  469.     if (display->isText)            // Center text vertically (if graphics).
  470.         return 0;
  471.     else
  472.         return (region->bottom + 2 - region->top - display->TextHeight("W")) / 2;
  473. }
  474.  
  475. void UIW_STRING::WordTabLeft()
  476. {
  477.     while ( cursor > text && WhiteSpace( *(cursor - 1) ) )
  478.         cursor--;
  479.     while ( cursor > text && NonWhiteSpace( *(cursor - 1) ) )
  480.         cursor--;
  481.     if (cursor < screenTop)
  482.         screenTop = cursor;
  483. }
  484.  
  485.