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

  1. //    Zinc Interface Library - FMTSTR.CPP
  2. //    COPYRIGHT (C) 1990, 1991.  All Rights Reserved.
  3. //    Zinc Software Incorporated.  Pleasant Grove, Utah  USA
  4.  
  5. #include "ui_win.hpp"
  6. #include <ctype.h>
  7. #include <stdlib.h>
  8. #include <string.h>
  9.  
  10. FS_STATE::FS_STATE(FS_STATE& src)
  11. {
  12.     isMarked = src.isMarked;
  13.     cursor = src.cursor;
  14.     int srcTextLen = (src.text) ? strlen(src.text) : 0;
  15.     text = new char[srcTextLen + 1];
  16.     strcpy(text, src.text);
  17. }
  18.  
  19. void FS_STATE::operator = (FS_STATE& src)
  20. {
  21.     isMarked = src.isMarked;
  22.     cursor = src.cursor;
  23.     strcpy(text, src.text);
  24. }
  25.  
  26. int FS_STATE::operator == (FS_STATE& rightOperand)
  27. {
  28.     return (isMarked == rightOperand.isMarked &&
  29.         cursor == rightOperand.cursor && !strcmp(text, rightOperand.text));
  30. }
  31.  
  32. int FS_STATE::operator != (FS_STATE& rightOperand)
  33. {
  34.     return (isMarked != rightOperand.isMarked ||
  35.         cursor != rightOperand.cursor || strcmp(this->text, rightOperand.text));
  36. }
  37.  
  38. UIW_FORMATTED_STRING::UIW_FORMATTED_STRING(int left, int top, int width,
  39.     char *_text, char *_editMask, char *_literalMask, USHORT _woFlags,
  40.     int (*_validate)(void *object, int ccode)) :
  41.     UI_WINDOW_OBJECT(left, top, width, 1, _woFlags, WOAF_NO_FLAGS)
  42. {
  43.     windowID[0] = ID_STRING;
  44.     windowID[1] = ID_FORMATTED_STRING;
  45.     search.type = ID_FORMATTED_STRING;
  46.  
  47.     Validate = _validate;
  48.     int editMaskLen = strlen(_editMask);
  49.     editMaskLen = Min(editMaskLen, width);
  50.     int litMaskLen = strlen(_literalMask);
  51.     editMask = new char[editMaskLen+1];
  52.     memcpy(editMask, _editMask, editMaskLen);
  53.     editMask[editMaskLen] = '\0';
  54.     literalMask = new char[editMaskLen+1];
  55.     memcpy(literalMask, _literalMask, editMaskLen);
  56.     literalMask[editMaskLen] = '\0';
  57.     if (litMaskLen < editMaskLen)
  58.         memset(literalMask + litMaskLen, '?', editMaskLen - litMaskLen);
  59.     maskLen = editMaskLen;
  60.     fieldWidth = width;
  61.     int textLen = TextLength();
  62.     int passedLength = ui_strlen(_text);
  63.     if (FlagSet(_woFlags, WOF_NO_ALLOCATE_DATA))
  64.         state.text = _text;
  65.     else
  66.     {
  67.         state.text = new char[textLen + 1];
  68.         int actualLen = Min(textLen, passedLength);
  69.         if (_text)
  70.             memcpy(state.text, _text, actualLen);
  71.         state.text[actualLen] = '\0';
  72.     }
  73. }
  74.  
  75. UIW_FORMATTED_STRING::~UIW_FORMATTED_STRING()
  76. {
  77.     if (FlagSet(woFlags, WOF_NO_ALLOCATE_DATA))
  78.         state.text = 0;                      // So FS_STATE destructor doesn't free it.
  79.     delete editMask;
  80.     delete literalMask;
  81. }
  82.  
  83. void UIW_FORMATTED_STRING::DataSet(char *newText)
  84. {
  85.     if (newText)
  86.     {
  87.         if (FlagSet(woFlags, WOF_NO_ALLOCATE_DATA))
  88.             state.text = newText;
  89.         else
  90.         {
  91.             delete state.text;
  92.             int textLen = TextLength();
  93.             state.text = new char[textLen + 1];
  94.             int actualLen = strlen(newText);
  95.             actualLen = Min(textLen, actualLen);
  96.             memcpy(state.text, newText, actualLen);
  97.             state.text[actualLen] = '\0';
  98.         }
  99.     }
  100.     UI_WINDOW_OBJECT::Redisplay(FALSE);
  101. }
  102.  
  103. int UIW_FORMATTED_STRING::Event(const UI_EVENT &event)
  104. {
  105.     int viewOnly = FlagSet(woFlags, WOF_VIEW_ONLY) ? TRUE : FALSE;
  106.      int ccode = UI_WINDOW_OBJECT::LogicalEvent(event, ID_STRING);
  107.     int cellWidth = display->TextWidth("W");
  108.     UI_REGION region;
  109.     UI_WINDOW_OBJECT::Border(0, region, 0);
  110.     int width = (region.right + 1 - region.left) / cellWidth;
  111.     USHORT key;
  112.     if (ccode == S_SIZE)
  113.     {
  114.         fieldWidth = width;
  115.         maskLen = strlen(editMask);
  116.         if (maskLen > fieldWidth)
  117.             maskLen = fieldWidth;
  118.         ccode = S_CREATE;
  119.     }
  120.     if (ccode == S_CREATE)
  121.     {
  122.         state.isMarked = FALSE;
  123.         state.cursor = 0;
  124.         FixText();
  125.     }
  126.     FS_STATE oldStateInfo(state);
  127.     UCHAR forceDisplay = FALSE;
  128.     UCHAR reDisplay = TRUE;
  129.     UCHAR displayCheckRegion = FALSE;
  130.     int needValidate = NeedsValidation();
  131.  
  132.     if (!FlagSet(woStatus, WOS_CURRENT))
  133.         state.isMarked = FALSE;
  134.     switch (ccode)
  135.     {
  136.     case E_KEY:
  137.         key = event.rawCode & 0xFF;
  138.         if ((key == '\b' || key >= ' ') && !viewOnly)
  139.         {
  140.             if (key == '\b')
  141.                 BackspaceKey();
  142.             else
  143.                 RegularKey(key);
  144.         }
  145.         else
  146.         {
  147.             reDisplay = FALSE;
  148.             ccode = S_UNKNOWN;
  149.         }
  150.         break;
  151.  
  152.     case L_LEFT:
  153.         woStatus |= WOS_NO_AUTO_CLEAR;
  154.         if (state.cursor > 0)
  155.             state.cursor--;
  156.         else
  157.             ccode = S_UNKNOWN;
  158.         break;
  159.  
  160.     case L_RIGHT:
  161.         woStatus |= WOS_NO_AUTO_CLEAR;
  162.         if (state.text[state.cursor + 1])
  163.             state.cursor++;
  164.         else
  165.             ccode = S_UNKNOWN;
  166.         break;
  167.  
  168.     case L_BOL:
  169.         woStatus |= WOS_NO_AUTO_CLEAR;
  170.         state.cursor = 0;
  171.         break;
  172.  
  173.     case L_EOL:
  174.         woStatus |= WOS_NO_AUTO_CLEAR;
  175.         state.cursor = ui_strlen(state.text) - 1;
  176.         break;
  177.  
  178.     case L_DELETE:
  179.         if (viewOnly)
  180.             break;
  181.         else if (state.isMarked)
  182.             CutBlock();
  183.         else
  184.             DeleteKey();
  185.         woStatus |= WOS_NO_AUTO_CLEAR;
  186.         break;
  187.  
  188.     case L_DELETE_EOL:
  189.         if (viewOnly)
  190.             break;
  191.         else if (state.isMarked)
  192.             CutBlock();
  193.         else
  194.         {
  195.             int originalCursor = state.cursor;
  196.             while (state.text[state.cursor])
  197.             {
  198.                 DeleteKey();
  199.                 state.cursor++;
  200.             }
  201.             state.cursor = originalCursor;
  202.         }
  203.         woStatus |= WOS_NO_AUTO_CLEAR;
  204.         break;
  205.  
  206.     case L_MARK:
  207.         state.isMarked = !state.isMarked;
  208.         break;
  209.  
  210.     case L_VIEW:
  211.         eventManager->DeviceState(event.type, DM_EDIT);
  212.         reDisplay = FALSE;
  213.         break;
  214.  
  215.     case L_CUT:
  216.         if (!viewOnly)
  217.         {
  218.             if (state.isMarked)
  219.                 CutBlock();
  220.             else
  221.                 reDisplay = FALSE;
  222.             break;
  223.         }
  224.         // If view only, treat a CUT as a copy.
  225.  
  226.     case L_COPY_MARK:
  227.         if (state.isMarked)
  228.             CopyBlock();
  229.         else
  230.             reDisplay = FALSE;
  231.         break;
  232.  
  233.     case L_CUT_PASTE:
  234.         if (state.isMarked)
  235.         {
  236.             if (viewOnly)
  237.                 CopyBlock();
  238.             else
  239.                 CutBlock();
  240.             break;
  241.         }
  242.         // Continue to L_PASTE.
  243.  
  244.     case L_PASTE:
  245.         if (!viewOnly)
  246.         {
  247.             if (event.type != E_KEY)
  248.                 SetCursor((event.position.column - region.left) / cellWidth, width);
  249.             PasteBlock();
  250.         }
  251.         break;
  252.  
  253.     case L_CONTINUE_MARK:
  254.         if (markColumn != (event.position.column - region.left) / cellWidth)
  255.             state.isMarked = TRUE;
  256.         break;
  257.  
  258.     case L_BEGIN_MARK:
  259.         state.isMarked = FALSE;
  260.         markColumn = (event.position.column - region.left) / cellWidth;
  261.         SetCursor(markColumn, width);
  262.         forceDisplay = TRUE;            // Force cursor to get updated.
  263.         break;
  264.  
  265.     case S_CURRENT:
  266.         woStatus &= ~WOS_UNANSWERED;
  267.         if (needValidate)
  268.             (*Validate)(this, ccode);
  269.         displayCheckRegion = TRUE;
  270.         break;
  271.  
  272.     case S_DISPLAY_ACTIVE:
  273.         displayCheckRegion = TRUE;
  274.         break;
  275.  
  276.     case S_NON_CURRENT:
  277.         if ( needValidate && (*Validate)(this, ccode) != 0 )
  278.         {
  279.             ccode = S_ERROR;
  280.             woStatus |= WOS_INVALID;
  281.             reDisplay = FALSE;
  282.             break;
  283.         }
  284.         woStatus &= ~WOS_INVALID;
  285.         // else fall through to S_DISPLAY_INACTIVE.
  286.  
  287.     case S_DISPLAY_INACTIVE:
  288.         state.isMarked = FALSE;
  289.         displayCheckRegion = TRUE;
  290.         break;
  291.  
  292.     case S_ERROR_RESPONSE:
  293.         woStatus |= event.rawCode;
  294.         forceDisplay = TRUE;
  295.         break;
  296.  
  297.     default:
  298.         ccode = UI_WINDOW_OBJECT::Event(event);
  299.         reDisplay = FALSE;
  300.         break;
  301.     }
  302.  
  303.     if (displayCheckRegion)
  304.     {
  305.         forceDisplay = TRUE;
  306.         if ( !UI_WINDOW_OBJECT::NeedsUpdate(event, ccode) &&
  307.               oldStateInfo == state )
  308.             reDisplay = FALSE;
  309.         else
  310.             UI_WINDOW_OBJECT::Border(ccode, region, lastPalette);
  311.     }
  312.  
  313.     char dText[256];
  314.     int cursorColumn;
  315.     if (reDisplay)
  316.     {
  317.         if (FlagSet(woStatus, WOS_UNANSWERED))
  318.             FixText();
  319.         if (forceDisplay || oldStateInfo != state)
  320.         {
  321.             cursorColumn = Expand(dText);
  322.             Redisplay(region, width, dText);
  323.             UpdateCursor(region, width, dText, cursorColumn);
  324.         }
  325.     }
  326.     else if (ccode == S_CURRENT)
  327.     {
  328.         cursorColumn = Expand(dText);
  329.         UpdateCursor(region, width, dText, cursorColumn);
  330.     }
  331.     return (ccode);
  332. }
  333.  
  334. void UIW_FORMATTED_STRING::BackspaceKey()
  335. {
  336.     if (state.cursor > 0)
  337.     {
  338.         state.cursor--;
  339.         DeleteKey();
  340.     }
  341.     woStatus |= WOS_CHANGED | WOS_NO_AUTO_CLEAR;
  342. }
  343.  
  344. int UIW_FORMATTED_STRING::CalcLeading(int width, char *dText)
  345. {
  346.     int textLen = strlen(dText);
  347.     int leading = 0;
  348.     if (woFlags & WOF_JUSTIFY_CENTER)
  349.         leading = Min((fieldWidth - textLen) / 2, width);
  350.     else if (woFlags & WOF_JUSTIFY_RIGHT)
  351.         leading = Min(fieldWidth - textLen, width);
  352.     if (leading < 0)
  353.         leading = 0;
  354.     return leading;
  355. }
  356.  
  357. void UIW_FORMATTED_STRING::CopyBlock()
  358. {
  359.     char dText[40];
  360.  
  361.     Expand(dText);
  362.  
  363.     pasteLength = (USHORT) strlen(dText);
  364.     if (pasteBuffer)
  365.         delete pasteBuffer;
  366.     pasteBuffer = new char[pasteLength];
  367.     if (pasteBuffer)
  368.         memcpy(pasteBuffer, dText, pasteLength);
  369.  
  370.     state.isMarked = FALSE;
  371.     woStatus |= WOS_CHANGED | WOS_NO_AUTO_CLEAR;
  372. }
  373.  
  374. void UIW_FORMATTED_STRING::CutBlock()
  375. {
  376.     CopyBlock();
  377.     int textIndex = 0;
  378.     for (int i = 0; state.text[textIndex] && i < maskLen; i++)
  379.     {
  380.         if (editMask[i] != 'L')
  381.             state.text[textIndex++] = literalMask[i];
  382.     }
  383.     state.cursor = 0;
  384.     woStatus |= WOS_CHANGED | WOS_NO_AUTO_CLEAR;
  385. }
  386.  
  387. void UIW_FORMATTED_STRING::DeleteKey()
  388. {
  389.     int column = ExpandedColumn();
  390.     // ## Borland bug: large model code generation problem on following line:
  391.     // state.text[state.cursor] = literalMask[column];
  392.     char literalChar = literalMask[column];
  393.     state.text[state.cursor] = literalChar;
  394.     woStatus |= WOS_CHANGED | WOS_NO_AUTO_CLEAR;
  395. }
  396.  
  397. int UIW_FORMATTED_STRING::Expand(char *destText)
  398. {
  399.     char *src = state.text;
  400.     int column = maskLen - 1;
  401.     for (int i = 0; i < maskLen; i++)
  402.     {
  403.         if (src - state.text == state.cursor)
  404.             column = i;
  405.         if ( editMask[i] == 'L' )
  406.             *destText++ = literalMask[i];
  407.         else
  408.             *destText++ = *src++;
  409.     }
  410.     *destText = 0;
  411.     return column;
  412. }
  413.  
  414. int UIW_FORMATTED_STRING::ExpandedColumn()
  415. {
  416.     char *src = state.text;
  417.     int column = maskLen - 1;
  418.     for (int i = 0; i < maskLen; i++)
  419.     {
  420.         if (src - state.text == state.cursor)
  421.             column = i;
  422.         if (editMask[i] != 'L')
  423.             src++;
  424.     }
  425.     return column;
  426. }
  427.  
  428. void UIW_FORMATTED_STRING::FixText()
  429. {
  430.     int textLen = TextLength();
  431.     if (FlagSet(woStatus, WOS_UNANSWERED))
  432.         memset(state.text, '\0', textLen + 1);
  433.     int copyLen = strlen(state.text);
  434.     int t = 0;
  435.     for (int i = 0; i < maskLen; i++)
  436.     {
  437.         if (editMask[i] != 'L')
  438.         {
  439.             int textValue = ValidateMask(editMask[i], state.text[t]);
  440.             if (t >= copyLen || !textValue)
  441.                 state.text[t] = literalMask[i];
  442.             else
  443.                 state.text[t] = textValue;
  444.             t++;
  445.         }
  446.     }
  447.     state.text[textLen] = '\0';
  448. }
  449.  
  450. void UIW_FORMATTED_STRING::PasteBlock()
  451. {
  452.     if (pasteBuffer && !state.isMarked)
  453.     {
  454.         int textIndex = 0;
  455.         int p = 0;
  456.         for (int i = 0; i < maskLen && p < pasteLength; i++)
  457.         {
  458.             if (editMask[i] != 'L')
  459.             {
  460.                 int textValue;
  461.                 do
  462.                 {
  463.                     textValue = ValidateMask(editMask[i], pasteBuffer[p]);
  464.                     p++;
  465.                 } while (!textValue && p < pasteLength);
  466.                 if (textValue)
  467.                     state.text[textIndex++] = textValue;
  468.             }
  469.         }
  470.         state.text[textIndex] = '\0';
  471.         FixText();
  472.         state.cursor = 0;
  473.         woStatus |= WOS_CHANGED | WOS_NO_AUTO_CLEAR;
  474.     }
  475. }
  476.  
  477. void UIW_FORMATTED_STRING::Redisplay(UI_REGION ®ion, short width, char *dText)
  478. {
  479.     short cellHeight = display->TextHeight("W");
  480.     short cellWidth = display->TextWidth("W");
  481.     if ( !display->isText || (woStatus & WOS_UNANSWERED) )
  482.         display->Rectangle(screenID, region, lastPalette, 0, TRUE);
  483.     int text_len = strlen(dText);
  484.     int leading = CalcLeading(width, dText);
  485.     text_len = Min(text_len, width - leading);
  486.     int trailing = width - text_len - leading;
  487.     int bottom = region.top + display->TextHeight("W") - 1;
  488.     if (bottom <= region.bottom && (woStatus & WOS_UNANSWERED) == 0)
  489.     {
  490.         if (!display->isText)            // Center text vertically.
  491.         {
  492.             int vertRoom = region.bottom + 1 - region.top - cellHeight;
  493.             region.top       += (vertRoom + 1) / 2;
  494.             region.bottom += (vertRoom + 1) / 2;
  495.         }
  496.         if (leading && display->isText)
  497.             display->Rectangle(screenID, region.left, region.top,
  498.                 region.left + leading - 1, region.bottom, lastPalette, 0, TRUE);
  499.         display->Text(screenID,
  500.             region.left + leading * cellWidth,
  501.             region.top, dText, lastPalette, text_len, FALSE);
  502.         if ( trailing && display->isText )
  503.         {
  504.             display->Rectangle(screenID,
  505.                 region.left + leading + text_len, region.top,
  506.                 region.left + leading + text_len + trailing - 1,
  507.                 region.bottom, lastPalette, 0, TRUE);
  508.         }
  509.         if (state.isMarked)
  510.             display->Text(screenID, region.left, region.top,
  511.                 NULL, _xorPalette, width, TRUE, TRUE);
  512.     }
  513. }
  514.  
  515. void UIW_FORMATTED_STRING::RegularKey(USHORT key)
  516. {
  517.     int textValue = ValidateMask(editMask[ExpandedColumn()], key);
  518.     if (textValue)
  519.     {
  520.         if (FlagSet(woFlags, WOF_AUTO_CLEAR) && !FlagSet(woStatus, WOS_NO_AUTO_CLEAR))
  521.         {
  522.             int textIndex = 0;
  523.             for (int i = 0; state.text[textIndex] && i < maskLen; i++)
  524.             {
  525.                 if (editMask[i] != 'L')
  526.                     state.text[textIndex++] = literalMask[i];
  527.             }
  528.             state.cursor = 0;
  529.         }
  530.         state.text[state.cursor] = textValue;
  531.         if (state.text[state.cursor + 1])
  532.             state.cursor++;
  533.         woStatus |= WOS_CHANGED | WOS_NO_AUTO_CLEAR;
  534.     }
  535. }
  536.  
  537. void UIW_FORMATTED_STRING::SetCursor(int column, int width)
  538. {
  539.     char expandedText[40];
  540.     Expand(expandedText);
  541.     int leading = 0;
  542.     int textLen = strlen(expandedText);
  543.     if (woFlags & WOF_JUSTIFY_CENTER)
  544.         leading = Min((fieldWidth - textLen) / 2, width);
  545.     else if (woFlags & WOF_JUSTIFY_RIGHT)
  546.         leading = Min(fieldWidth - textLen, width);
  547.     column -= leading;
  548.     column = Min(column, maskLen);
  549.     int match = 0;
  550.     for (int i = 0; i < column; i++)
  551.     {
  552.         if (editMask[i] != 'L')
  553.             match++;
  554.     }
  555.     state.cursor = match;
  556. }
  557.  
  558. int UIW_FORMATTED_STRING::TextLength()
  559. {
  560.     int textLen = 0;
  561.     for (int i = 0; i < maskLen; i++)
  562.     {
  563.         if (editMask[i] != 'L')
  564.             textLen++;
  565.     }
  566.     return textLen;
  567. }
  568.  
  569. void UIW_FORMATTED_STRING::UpdateCursor(UI_REGION ®ion, int width,
  570.     char *dText, int cursorColumn)
  571. {
  572.     short cellWidth = display->TextWidth("W");
  573.     int leading = CalcLeading(width, dText);
  574.     if (  FlagSet(woStatus, WOS_CURRENT) &&
  575.          !FlagSet(woAdvancedStatus, WOAS_TOO_SMALL) &&
  576.          !FlagSet(woFlags, WOF_VIEW_ONLY) &&
  577.          (leading + cursorColumn < width) )
  578.     {
  579.         int trueColumn = region.left +
  580.             (leading + cursorColumn) * cellWidth;
  581.         if (trueColumn >= 0 && trueColumn < display->columns &&
  582.             region.top >= 0 && region.top < display->lines )
  583.         {
  584.             eventManager->DevicePosition(E_CURSOR, trueColumn, region.top);
  585.             eventManager->DeviceState(E_CURSOR, DC_OVERTYPE);
  586.         }
  587.     }
  588. }
  589.  
  590. int UIW_FORMATTED_STRING::ValidateMask(int editValue, int textValue)
  591. {
  592.     int isAlpha = (textValue == ' ' || isalpha(textValue));
  593.     int isDigit = isdigit(textValue);
  594.     if (isupper(editValue))
  595.         textValue = toupper(textValue);
  596.     editValue = toupper(editValue);
  597.     if ((editValue == 'X' && textValue >= ' ' && textValue <= '~') ||
  598.         (editValue == 'N' && isDigit) ||
  599.         (editValue == 'A' && isAlpha) ||
  600.         (editValue == 'C' && (isDigit || isAlpha)))
  601.         return (textValue);
  602.     else
  603.         return (0);
  604. }
  605.  
  606. #ifdef ZIL_LOAD
  607. UIW_FORMATTED_STRING::UIW_FORMATTED_STRING(const char *name, UI_STORAGE *file, USHORT loadFlags) :
  608.     UI_WINDOW_OBJECT(name, file, loadFlags | L_SUB_LEVEL),
  609.     fieldWidth(relative.right - relative.left + 1)
  610. {
  611.     windowID[0] = ID_FORMATTED_STRING;
  612.  
  613.     if (!file)
  614.         file = _storage;
  615.     file->Load(&editMask);
  616.     file->Load(&literalMask);
  617.     file->Load(&state.text);
  618.     maskLen = strlen(editMask);
  619.     if (!FlagSet(loadFlags, L_SUB_LEVEL) && FlagSet(file->stStatus, STS_TEMPORARY))
  620.         delete file;
  621. }
  622. #endif
  623.  
  624. #ifdef ZIL_STORE
  625. void UIW_FORMATTED_STRING::Store(const char *name, UI_STORAGE *file, USHORT storeFlags)
  626. {
  627.     UI_WINDOW_OBJECT::Store(name, file, storeFlags | S_SUB_LEVEL);
  628.     file->Store(editMask);
  629.     file->Store(literalMask);
  630.     file->Store(state.text);
  631.     if (!FlagSet(storeFlags, S_SUB_LEVEL))
  632.         file->ObjectSize(name, search);
  633. }
  634. #endif
  635.  
  636.